mirror of
https://github.com/pocoproject/poco.git
synced 2025-03-28 09:32:52 +01:00
NTLM (proxy) authentication support for HTTPClientSession
This commit is contained in:
parent
da7de5e586
commit
0f3f11a3b2
@ -32,7 +32,8 @@ objects = \
|
||||
RemoteSyslogChannel RemoteSyslogListener SMTPChannel \
|
||||
WebSocket WebSocketImpl \
|
||||
OAuth10Credentials OAuth20Credentials \
|
||||
PollSet UDPClient UDPServerParams
|
||||
PollSet UDPClient UDPServerParams \
|
||||
NTLMCredentials HTTPNTLMCredentials
|
||||
|
||||
target = PocoNet
|
||||
target_version = $(LIBVERSION)
|
||||
|
@ -33,6 +33,9 @@ class HTTPResponse;
|
||||
class Net_API HTTPAuthenticationParams: public NameValueCollection
|
||||
/// Collection of name-value pairs of HTTP authentication header (i.e.
|
||||
/// "realm", "qop", "nonce" in case of digest authentication header).
|
||||
///
|
||||
/// For NTLM, the base64-encoded NTLM message is available from
|
||||
/// the "NTLM" property.
|
||||
{
|
||||
public:
|
||||
HTTPAuthenticationParams();
|
||||
@ -89,6 +92,7 @@ public:
|
||||
/// request or response authentication header.
|
||||
|
||||
static const std::string REALM;
|
||||
static const std::string NTLM;
|
||||
static const std::string WWW_AUTHENTICATE;
|
||||
static const std::string PROXY_AUTHENTICATE;
|
||||
|
||||
|
@ -20,6 +20,9 @@
|
||||
|
||||
#include "Poco/Net/Net.h"
|
||||
#include "Poco/Net/HTTPSession.h"
|
||||
#include "Poco/Net/HTTPBasicCredentials.h"
|
||||
#include "Poco/Net/HTTPDigestCredentials.h"
|
||||
#include "Poco/Net/HTTPNTLMCredentials.h"
|
||||
#include "Poco/Net/SocketAddress.h"
|
||||
#include "Poco/SharedPtr.h"
|
||||
#include <istream>
|
||||
@ -62,11 +65,20 @@ class Net_API HTTPClientSession: public HTTPSession
|
||||
/// set up a session through a proxy.
|
||||
{
|
||||
public:
|
||||
enum ProxyAuthentication
|
||||
{
|
||||
PROXY_AUTH_NONE, /// No proxy authentication
|
||||
PROXY_AUTH_HTTP_BASIC, /// HTTP Basic proxy authentication (default, if username and password are supplied)
|
||||
PROXY_AUTH_HTTP_DIGEST, /// HTTP Digest proxy authentication
|
||||
PROXY_AUTH_NTLM /// NTLMv2 proxy authentication
|
||||
};
|
||||
|
||||
struct ProxyConfig
|
||||
/// HTTP proxy server configuration.
|
||||
{
|
||||
ProxyConfig():
|
||||
port(HTTP_PORT)
|
||||
port(HTTP_PORT),
|
||||
authMethod(PROXY_AUTH_HTTP_BASIC)
|
||||
{
|
||||
}
|
||||
|
||||
@ -82,6 +94,9 @@ public:
|
||||
/// A regular expression defining hosts for which the proxy should be bypassed,
|
||||
/// e.g. "localhost|127\.0\.0\.1|192\.168\.0\.\d+". Can also be an empty
|
||||
/// string to disable proxy bypassing.
|
||||
|
||||
ProxyAuthentication authMethod;
|
||||
/// The authentication method to use - HTTP Basic or NTLM.
|
||||
};
|
||||
|
||||
HTTPClientSession();
|
||||
@ -110,47 +125,47 @@ public:
|
||||
///
|
||||
/// The host must not be changed once there is an
|
||||
/// open connection to the server.
|
||||
|
||||
|
||||
const std::string& getHost() const;
|
||||
/// Returns the host name of the target HTTP server.
|
||||
|
||||
|
||||
void setPort(Poco::UInt16 port);
|
||||
/// Sets the port number of the target HTTP server.
|
||||
///
|
||||
/// The port number must not be changed once there is an
|
||||
/// open connection to the server.
|
||||
|
||||
|
||||
Poco::UInt16 getPort() const;
|
||||
/// Returns the port number of the target HTTP server.
|
||||
|
||||
void setProxy(const std::string& host, Poco::UInt16 port = HTTPSession::HTTP_PORT);
|
||||
/// Sets the proxy host name and port number.
|
||||
|
||||
|
||||
void setProxyHost(const std::string& host);
|
||||
/// Sets the host name of the proxy server.
|
||||
|
||||
|
||||
void setProxyPort(Poco::UInt16 port);
|
||||
/// Sets the port number of the proxy server.
|
||||
|
||||
|
||||
const std::string& getProxyHost() const;
|
||||
/// Returns the proxy host name.
|
||||
|
||||
|
||||
Poco::UInt16 getProxyPort() const;
|
||||
/// Returns the proxy port number.
|
||||
|
||||
|
||||
void setProxyCredentials(const std::string& username, const std::string& password);
|
||||
/// Sets the username and password for proxy authentication.
|
||||
/// Only Basic authentication is supported.
|
||||
|
||||
|
||||
void setProxyUsername(const std::string& username);
|
||||
/// Sets the username for proxy authentication.
|
||||
/// Only Basic authentication is supported.
|
||||
|
||||
const std::string& getProxyUsername() const;
|
||||
/// Returns the username for proxy authentication.
|
||||
|
||||
|
||||
void setProxyPassword(const std::string& password);
|
||||
/// Sets the password for proxy authentication.
|
||||
/// Sets the password for proxy authentication.
|
||||
/// Only Basic authentication is supported.
|
||||
|
||||
const std::string& getProxyPassword() const;
|
||||
@ -177,10 +192,10 @@ public:
|
||||
|
||||
void setKeepAliveTimeout(const Poco::Timespan& timeout);
|
||||
/// Sets the connection timeout for HTTP connections.
|
||||
|
||||
|
||||
const Poco::Timespan& getKeepAliveTimeout() const;
|
||||
/// Returns the connection timeout for HTTP connections.
|
||||
|
||||
|
||||
virtual std::ostream& sendRequest(HTTPRequest& request);
|
||||
/// Sends the header for the given HTTP request to
|
||||
/// the server.
|
||||
@ -200,9 +215,9 @@ public:
|
||||
/// be reused and persistent connections are enabled
|
||||
/// to ensure a new connection will be set up
|
||||
/// for the next request.
|
||||
|
||||
|
||||
virtual std::istream& receiveResponse(HTTPResponse& response);
|
||||
/// Receives the header for the response to the previous
|
||||
/// Receives the header for the response to the previous
|
||||
/// HTTP request.
|
||||
///
|
||||
/// The returned input stream can be used to read
|
||||
@ -213,7 +228,7 @@ public:
|
||||
/// It must be ensured that the response stream
|
||||
/// is fully consumed before sending a new request
|
||||
/// and persistent connections are enabled. Otherwise,
|
||||
/// the unread part of the response body may be treated as
|
||||
/// the unread part of the response body may be treated as
|
||||
/// part of the next request's response header, resulting
|
||||
/// in a Poco::Net::MessageException being thrown.
|
||||
///
|
||||
@ -224,17 +239,17 @@ public:
|
||||
/// be reused and persistent connections are enabled
|
||||
/// to ensure a new connection will be set up
|
||||
/// for the next request.
|
||||
|
||||
|
||||
virtual bool peekResponse(HTTPResponse& response);
|
||||
/// If the request contains a "Expect: 100-continue" header,
|
||||
/// (see HTTPRequest::setExpectContinue()) this method can be
|
||||
/// used to check whether the server has sent a 100 Continue response
|
||||
/// (see HTTPRequest::setExpectContinue()) this method can be
|
||||
/// used to check whether the server has sent a 100 Continue response
|
||||
/// before continuing with the request, i.e. sending the request body,
|
||||
/// after calling sendRequest().
|
||||
///
|
||||
/// Returns true if the server has responded with 100 Continue,
|
||||
/// otherwise false. The HTTPResponse object contains the
|
||||
/// response sent by the server.
|
||||
/// response sent by the server.
|
||||
///
|
||||
/// In any case, receiveResponse() must be called afterwards as well in
|
||||
/// order to complete the request. The same HTTPResponse object
|
||||
@ -254,11 +269,11 @@ public:
|
||||
/// or receiveResponse() throws an exception, or
|
||||
/// the request or response stream changes into
|
||||
/// fail or bad state, but not eof state).
|
||||
|
||||
|
||||
virtual bool secure() const;
|
||||
/// Return true iff the session uses SSL or TLS,
|
||||
/// or false otherwise.
|
||||
|
||||
|
||||
bool bypassProxy() const;
|
||||
/// Returns true if the proxy should be bypassed
|
||||
/// for the current host.
|
||||
@ -268,32 +283,45 @@ protected:
|
||||
{
|
||||
DEFAULT_KEEP_ALIVE_TIMEOUT = 8
|
||||
};
|
||||
|
||||
|
||||
void reconnect();
|
||||
/// Connects the underlying socket to the HTTP server.
|
||||
|
||||
int write(const char* buffer, std::streamsize length);
|
||||
/// Tries to re-connect if keep-alive is on.
|
||||
|
||||
|
||||
std::ostream& sendRequestImpl(const HTTPRequest& request);
|
||||
/// Sends the given HTTPRequest over an existing connection.
|
||||
|
||||
virtual std::string proxyRequestPrefix() const;
|
||||
/// Returns the prefix prepended to the URI for proxy requests
|
||||
/// (e.g., "http://myhost.com").
|
||||
|
||||
virtual bool mustReconnect() const;
|
||||
/// Checks if we can reuse a persistent connection.
|
||||
|
||||
|
||||
virtual void proxyAuthenticate(HTTPRequest& request);
|
||||
/// Sets the proxy credentials (Proxy-Authorization header), if
|
||||
/// proxy username and password have been set.
|
||||
|
||||
void proxyAuthenticateImpl(HTTPRequest& request);
|
||||
void proxyAuthenticateImpl(HTTPRequest& request, const ProxyConfig& proxyConfig);
|
||||
/// Sets the proxy credentials (Proxy-Authorization header), if
|
||||
/// proxy username and password have been set.
|
||||
|
||||
|
||||
void proxyAuthenticateDigest(HTTPRequest& request);
|
||||
/// Initiates a HTTP Digest authentication handshake with the proxy.
|
||||
|
||||
void proxyAuthenticateNTLM(HTTPRequest& request);
|
||||
/// Initiates a HTTP NTLM authentication handshake with the proxy.
|
||||
|
||||
void sendChallengeRequest(const HTTPRequest& request, HTTPResponse& response);
|
||||
/// Sends a probe request for Digest and NTLM authentication
|
||||
/// to obtain the server challenge.
|
||||
|
||||
StreamSocket proxyConnect();
|
||||
/// Sends a CONNECT request to the proxy server and returns
|
||||
/// a StreamSocket for the resulting connection.
|
||||
|
||||
|
||||
void proxyTunnel();
|
||||
/// Calls proxyConnect() and attaches the resulting StreamSocket
|
||||
/// to the HTTPClientSession.
|
||||
@ -310,9 +338,13 @@ private:
|
||||
bool _responseReceived;
|
||||
Poco::SharedPtr<std::ostream> _pRequestStream;
|
||||
Poco::SharedPtr<std::istream> _pResponseStream;
|
||||
HTTPBasicCredentials _proxyBasicCreds;
|
||||
HTTPDigestCredentials _proxyDigestCreds;
|
||||
HTTPNTLMCredentials _proxyNTLMCreds;
|
||||
bool _ntlmProxyAuthenticated;
|
||||
|
||||
static ProxyConfig _globalProxyConfig;
|
||||
|
||||
|
||||
HTTPClientSession(const HTTPClientSession&);
|
||||
HTTPClientSession& operator = (const HTTPClientSession&);
|
||||
|
||||
|
@ -20,6 +20,7 @@
|
||||
|
||||
|
||||
#include "Poco/Net/HTTPDigestCredentials.h"
|
||||
#include "Poco/Net/HTTPNTLMCredentials.h"
|
||||
|
||||
|
||||
namespace Poco {
|
||||
@ -37,13 +38,13 @@ class HTTPResponse;
|
||||
|
||||
class Net_API HTTPCredentials
|
||||
/// This is a utility class for working with HTTP
|
||||
/// authentication (basic or digest) in HTTPRequest objects.
|
||||
/// authentication (Basic, Digest or NTLM) in HTTPRequest objects.
|
||||
///
|
||||
/// Usage is as follows:
|
||||
/// First, create a HTTPCredentials object containing
|
||||
/// the username and password.
|
||||
/// Poco::Net::HTTPCredentials creds("user", "s3cr3t");
|
||||
///
|
||||
///
|
||||
/// Second, send the HTTP request with Poco::Net::HTTPClientSession.
|
||||
/// Poco::Net::HTTPClientSession session("pocoproject.org");
|
||||
/// Poco::Net::HTTPRequest request(HTTPRequest::HTTP_GET, "/index.html", HTTPMessage::HTTP_1_1);
|
||||
@ -51,7 +52,7 @@ class Net_API HTTPCredentials
|
||||
/// Poco::Net::HTTPResponse;
|
||||
/// std::istream& istr = session.receiveResponse(response);
|
||||
///
|
||||
/// If the server responds with a 401 status, authenticate the
|
||||
/// If the server responds with a 401 status, authenticate the
|
||||
/// request and resend it:
|
||||
/// if (response.getStatus() == Poco::Net::HTTPResponse::HTTP_UNAUTHORIZED)
|
||||
/// {
|
||||
@ -61,7 +62,7 @@ class Net_API HTTPCredentials
|
||||
/// }
|
||||
///
|
||||
/// To perform multiple authenticated requests, call updateAuthInfo()
|
||||
/// instead of authenticate() on subsequent requests.
|
||||
/// instead of authenticate() on subsequent requests.
|
||||
/// creds.updateAuthInfo(request);
|
||||
/// session.sendRequest(request);
|
||||
/// ...
|
||||
@ -132,17 +133,26 @@ public:
|
||||
static bool isDigestCredentials(const std::string& header);
|
||||
/// Returns true if authentication header is for Digest authentication.
|
||||
|
||||
static bool isNTLMCredentials(const std::string& header);
|
||||
/// Returns true if authentication header is for NTLM authentication.
|
||||
|
||||
static bool hasBasicCredentials(const HTTPRequest& request);
|
||||
/// Returns true if Authorization with Basic credentials header is present in the request.
|
||||
/// Returns true if an Authorization header with Basic credentials is present in the request.
|
||||
|
||||
static bool hasDigestCredentials(const HTTPRequest& request);
|
||||
/// Returns true if Authorization with Digest credentials header is present in the request.
|
||||
/// Returns true if an Authorization header with Digest credentials is present in the request.
|
||||
|
||||
static bool hasNTLMCredentials(const HTTPRequest& request);
|
||||
/// Returns true if an Authorization header with NTLM credentials is present in the request.
|
||||
|
||||
static bool hasProxyBasicCredentials(const HTTPRequest& request);
|
||||
/// Returns true if Authorization with Basic credentials header is present in the request.
|
||||
/// Returns true if a Proxy-Authorization header with Basic credentials is present in the request.
|
||||
|
||||
static bool hasProxyDigestCredentials(const HTTPRequest& request);
|
||||
/// Returns true if Authorization with Digest credentials header is present in the request.
|
||||
/// Returns true if a Proxy-Authorization header with Digest credentials is present in the request.
|
||||
|
||||
static bool hasProxyNTLMCredentials(const HTTPRequest& request);
|
||||
/// Returns true if a Proxy-Authorization header with Digest credentials is present in the request.
|
||||
|
||||
static void extractCredentials(const std::string& userInfo, std::string& username, std::string& password);
|
||||
/// Extracts username and password from user:password information string.
|
||||
@ -155,6 +165,7 @@ private:
|
||||
HTTPCredentials& operator = (const HTTPCredentials&);
|
||||
|
||||
HTTPDigestCredentials _digest;
|
||||
HTTPNTLMCredentials _ntlm;
|
||||
};
|
||||
|
||||
|
||||
@ -172,7 +183,7 @@ inline const std::string& HTTPCredentials::getUsername() const
|
||||
return _digest.getUsername();
|
||||
}
|
||||
|
||||
|
||||
|
||||
inline void HTTPCredentials::setPassword(const std::string& password)
|
||||
{
|
||||
_digest.setPassword(password);
|
||||
|
@ -39,22 +39,22 @@ class Net_API HTTPMessage: public MessageHeader
|
||||
public:
|
||||
void setVersion(const std::string& version);
|
||||
/// Sets the HTTP version for this message.
|
||||
|
||||
|
||||
const std::string& getVersion() const;
|
||||
/// Returns the HTTP version for this message.
|
||||
|
||||
|
||||
void setContentLength(std::streamsize length);
|
||||
/// Sets the Content-Length header.
|
||||
///
|
||||
/// If length is UNKNOWN_CONTENT_LENGTH, removes
|
||||
/// the Content-Length header.
|
||||
|
||||
|
||||
std::streamsize getContentLength() const;
|
||||
/// Returns the content length for this message,
|
||||
/// which may be UNKNOWN_CONTENT_LENGTH if
|
||||
/// no Content-Length header is present.
|
||||
|
||||
#if defined(POCO_HAVE_INT64)
|
||||
#if defined(POCO_HAVE_INT64)
|
||||
void setContentLength64(Poco::Int64 length);
|
||||
/// Sets the Content-Length header.
|
||||
///
|
||||
@ -89,30 +89,30 @@ public:
|
||||
/// Normally, this is the value of the Transfer-Encoding
|
||||
/// header field. If no such field is present,
|
||||
/// returns IDENTITY_TRANSFER_CODING.
|
||||
|
||||
|
||||
void setChunkedTransferEncoding(bool flag);
|
||||
/// If flag is true, sets the Transfer-Encoding header to
|
||||
/// chunked. Otherwise, removes the Transfer-Encoding
|
||||
/// header.
|
||||
|
||||
|
||||
bool getChunkedTransferEncoding() const;
|
||||
/// Returns true if the Transfer-Encoding header is set
|
||||
/// and its value is chunked.
|
||||
|
||||
|
||||
void setContentType(const std::string& mediaType);
|
||||
/// Sets the content type for this message.
|
||||
///
|
||||
/// Specify NO_CONTENT_TYPE to remove the
|
||||
/// Content-Type header.
|
||||
|
||||
void setContentType(const MediaType& mediaType);
|
||||
|
||||
void setContentType(const MediaType& mediaType);
|
||||
/// Sets the content type for this message.
|
||||
|
||||
|
||||
const std::string& getContentType() const;
|
||||
/// Returns the content type for this message.
|
||||
///
|
||||
/// If no Content-Type header is present,
|
||||
/// returns UNKNOWN_CONTENT_TYPE.
|
||||
/// If no Content-Type header is present,
|
||||
/// returns UNKNOWN_CONTENT_TYPE.
|
||||
|
||||
void setKeepAlive(bool keepAlive);
|
||||
/// Sets the value of the Connection header field.
|
||||
@ -134,12 +134,13 @@ public:
|
||||
|
||||
static const int UNKNOWN_CONTENT_LENGTH;
|
||||
static const std::string UNKNOWN_CONTENT_TYPE;
|
||||
|
||||
|
||||
static const std::string CONTENT_LENGTH;
|
||||
static const std::string CONTENT_TYPE;
|
||||
static const std::string TRANSFER_ENCODING;
|
||||
static const std::string CONNECTION;
|
||||
|
||||
static const std::string PROXY_CONNECTION;
|
||||
|
||||
static const std::string CONNECTION_KEEP_ALIVE;
|
||||
static const std::string CONNECTION_CLOSE;
|
||||
|
||||
@ -153,13 +154,16 @@ protected:
|
||||
/// Creates the HTTPMessage and sets
|
||||
/// the version.
|
||||
|
||||
HTTPMessage(const HTTPMessage& other);
|
||||
/// Copy constructor.
|
||||
|
||||
HTTPMessage& operator = (const HTTPMessage& other);
|
||||
/// Assignment operator.
|
||||
|
||||
virtual ~HTTPMessage();
|
||||
/// Destroys the HTTPMessage.
|
||||
|
||||
|
||||
private:
|
||||
HTTPMessage(const HTTPMessage&);
|
||||
HTTPMessage& operator = (const HTTPMessage&);
|
||||
|
||||
std::string _version;
|
||||
};
|
||||
|
||||
|
128
Net/include/Poco/Net/HTTPNTLMCredentials.h
Normal file
128
Net/include/Poco/Net/HTTPNTLMCredentials.h
Normal file
@ -0,0 +1,128 @@
|
||||
//
|
||||
// HTTPNTLMCredentials.h
|
||||
//
|
||||
// Library: Net
|
||||
// Package: HTTP
|
||||
// Module: HTTPNTLMCredentials
|
||||
//
|
||||
// Definition of the HTTPNTLMCredentials class.
|
||||
//
|
||||
// Copyright (c) 2019, Applied Informatics Software Engineering GmbH.
|
||||
// and Contributors.
|
||||
//
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
//
|
||||
|
||||
|
||||
#ifndef Net_HTTPNTLMCredentials_INCLUDED
|
||||
#define Net_HTTPNTLMCredentials_INCLUDED
|
||||
|
||||
|
||||
#include "Poco/Net/Net.h"
|
||||
|
||||
|
||||
namespace Poco {
|
||||
namespace Net {
|
||||
|
||||
|
||||
class HTTPRequest;
|
||||
class HTTPResponse;
|
||||
|
||||
|
||||
class Net_API HTTPNTLMCredentials
|
||||
/// This is a utility class for working with
|
||||
/// HTTP NTLMv2 Authentication in HTTPRequest
|
||||
/// objects.
|
||||
{
|
||||
public:
|
||||
HTTPNTLMCredentials();
|
||||
/// Creates an empty HTTPNTLMCredentials object.
|
||||
|
||||
HTTPNTLMCredentials(const std::string& username, const std::string& password);
|
||||
/// Creates a HTTPNTLMCredentials object with the given username and password.
|
||||
|
||||
~HTTPNTLMCredentials();
|
||||
/// Destroys the HTTPNTLMCredentials.
|
||||
|
||||
void reset();
|
||||
/// Resets the HTTPNTLMCredentials object to a clean state.
|
||||
|
||||
void setUsername(const std::string& username);
|
||||
/// Sets the username.
|
||||
|
||||
const std::string& getUsername() const;
|
||||
/// Returns the username.
|
||||
|
||||
void setPassword(const std::string& password);
|
||||
/// Sets the password.
|
||||
|
||||
const std::string& getPassword() const;
|
||||
/// Returns the password.
|
||||
|
||||
void authenticate(HTTPRequest& request, const HTTPResponse& response);
|
||||
/// Parses WWW-Authenticate header of the HTTPResponse, initializes
|
||||
/// internal state, and adds authentication information to the given HTTPRequest.
|
||||
|
||||
void authenticate(HTTPRequest& request, const std::string& ntlmChallengeBase64);
|
||||
/// Initializes internal state according to information from the
|
||||
/// ntlmChallengeBase64, and adds authentication
|
||||
/// information to the given HTTPRequest.
|
||||
///
|
||||
/// Throws InvalidArgumentException if responseAuthParams is
|
||||
/// invalid.
|
||||
|
||||
void updateAuthInfo(HTTPRequest& request);
|
||||
/// Updates internal state and adds authentication information to
|
||||
/// the given HTTPRequest.
|
||||
|
||||
void proxyAuthenticate(HTTPRequest& request, const HTTPResponse& response);
|
||||
/// Parses Proxy-Authenticate header of the HTTPResponse, initializes
|
||||
/// internal state, and adds proxy authentication information to the given HTTPRequest.
|
||||
|
||||
void proxyAuthenticate(HTTPRequest& request, const std::string& ntlmChallengeBase64);
|
||||
/// Initializes internal state according to information from the
|
||||
/// HTTPAuthenticationParams of the response, and adds proxy authentication
|
||||
/// information to the given HTTPRequest.
|
||||
///
|
||||
/// Throws InvalidArgumentException if HTTPAuthenticationParams is
|
||||
/// invalid or some required parameter is missing.
|
||||
/// Throws NotImplementedException in case of unsupported digest
|
||||
/// algorithm or quality of protection method.
|
||||
|
||||
void updateProxyAuthInfo(HTTPRequest& request);
|
||||
/// Updates internal state and adds proxy authentication information to
|
||||
/// the given HTTPRequest.
|
||||
|
||||
static const std::string SCHEME;
|
||||
|
||||
private:
|
||||
HTTPNTLMCredentials(const HTTPNTLMCredentials&);
|
||||
HTTPNTLMCredentials& operator = (const HTTPNTLMCredentials&);
|
||||
|
||||
std::string createNTLMMessage(const std::string& ntlmChallengeBase64);
|
||||
static void splitUsername(const std::string& usernameAndDomain, std::string& username, std::string& domain);
|
||||
|
||||
std::string _username;
|
||||
std::string _password;
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// inlines
|
||||
//
|
||||
inline const std::string& HTTPNTLMCredentials::getUsername() const
|
||||
{
|
||||
return _username;
|
||||
}
|
||||
|
||||
|
||||
inline const std::string& HTTPNTLMCredentials::getPassword() const
|
||||
{
|
||||
return _password;
|
||||
}
|
||||
|
||||
|
||||
} } // namespace Poco::Net
|
||||
|
||||
|
||||
#endif // Net_HTTPNTLMCredentials_INCLUDED
|
@ -38,20 +38,26 @@ class Net_API HTTPRequest: public HTTPMessage
|
||||
public:
|
||||
HTTPRequest();
|
||||
/// Creates a GET / HTTP/1.0 HTTP request.
|
||||
|
||||
HTTPRequest(const std::string& version);
|
||||
|
||||
explicit HTTPRequest(const std::string& version);
|
||||
/// Creates a GET / HTTP/1.x request with
|
||||
/// the given version (HTTP/1.0 or HTTP/1.1).
|
||||
|
||||
|
||||
HTTPRequest(const std::string& method, const std::string& uri);
|
||||
/// Creates a HTTP/1.0 request with the given method and URI.
|
||||
|
||||
HTTPRequest(const std::string& method, const std::string& uri, const std::string& version);
|
||||
/// Creates a HTTP request with the given method, URI and version.
|
||||
|
||||
HTTPRequest(const HTTPRequest& other);
|
||||
/// Creates a HTTP request by copying another one.
|
||||
|
||||
virtual ~HTTPRequest();
|
||||
/// Destroys the HTTPRequest.
|
||||
|
||||
HTTPRequest& operator = (const HTTPRequest&);
|
||||
/// Assignment operator.
|
||||
|
||||
void setMethod(const std::string& method);
|
||||
/// Sets the method.
|
||||
|
||||
@ -60,20 +66,20 @@ public:
|
||||
|
||||
void setURI(const std::string& uri);
|
||||
/// Sets the request URI.
|
||||
|
||||
|
||||
const std::string& getURI() const;
|
||||
/// Returns the request URI.
|
||||
|
||||
|
||||
void setHost(const std::string& host);
|
||||
/// Sets the value of the Host header field.
|
||||
|
||||
|
||||
void setHost(const std::string& host, Poco::UInt16 port);
|
||||
/// Sets the value of the Host header field.
|
||||
///
|
||||
/// If the given port number is a non-standard
|
||||
/// port number (other than 80 or 443), it is
|
||||
/// included in the Host header field.
|
||||
|
||||
|
||||
const std::string& getHost() const;
|
||||
/// Returns the value of the Host header field.
|
||||
///
|
||||
@ -83,7 +89,7 @@ public:
|
||||
void setCookies(const NameValueCollection& cookies);
|
||||
/// Adds a Cookie header with the names and
|
||||
/// values from cookies.
|
||||
|
||||
|
||||
void getCookies(NameValueCollection& cookies) const;
|
||||
/// Fills cookies with the cookies extracted
|
||||
/// from the Cookie headers in the request.
|
||||
@ -91,18 +97,21 @@ public:
|
||||
bool hasCredentials() const;
|
||||
/// Returns true iff the request contains authentication
|
||||
/// information in the form of an Authorization header.
|
||||
|
||||
|
||||
void getCredentials(std::string& scheme, std::string& authInfo) const;
|
||||
/// Returns the authentication scheme and additional authentication
|
||||
/// information contained in this request.
|
||||
///
|
||||
/// Throws a NotAuthenticatedException if no authentication information
|
||||
/// is contained in the request.
|
||||
|
||||
|
||||
void setCredentials(const std::string& scheme, const std::string& authInfo);
|
||||
/// Sets the authentication scheme and information for
|
||||
/// this request.
|
||||
|
||||
void removeCredentials();
|
||||
/// Removes any credentials from the request.
|
||||
|
||||
bool getExpectContinue() const;
|
||||
/// Returns true if the request contains an
|
||||
/// "Expect: 100-continue" header.
|
||||
@ -110,22 +119,25 @@ public:
|
||||
void setExpectContinue(bool expectContinue);
|
||||
/// Adds a "Expect: 100-continue" header to the request if
|
||||
/// expectContinue is true, otherwise removes the Expect header.
|
||||
|
||||
|
||||
bool hasProxyCredentials() const;
|
||||
/// Returns true iff the request contains proxy authentication
|
||||
/// information in the form of an Proxy-Authorization header.
|
||||
|
||||
|
||||
void getProxyCredentials(std::string& scheme, std::string& authInfo) const;
|
||||
/// Returns the proxy authentication scheme and additional proxy authentication
|
||||
/// information contained in this request.
|
||||
///
|
||||
/// Throws a NotAuthenticatedException if no proxy authentication information
|
||||
/// is contained in the request.
|
||||
|
||||
|
||||
void setProxyCredentials(const std::string& scheme, const std::string& authInfo);
|
||||
/// Sets the proxy authentication scheme and information for
|
||||
/// this request.
|
||||
|
||||
void removeProxyCredentials();
|
||||
/// Removes any proxy credentials from the request.
|
||||
|
||||
void write(std::ostream& ostr) const;
|
||||
/// Writes the HTTP request to the given
|
||||
/// output stream.
|
||||
@ -133,7 +145,7 @@ public:
|
||||
void read(std::istream& istr);
|
||||
/// Reads the HTTP request from the
|
||||
/// given input stream.
|
||||
|
||||
|
||||
static const std::string HTTP_GET;
|
||||
static const std::string HTTP_HEAD;
|
||||
static const std::string HTTP_PUT;
|
||||
@ -143,7 +155,7 @@ public:
|
||||
static const std::string HTTP_TRACE;
|
||||
static const std::string HTTP_CONNECT;
|
||||
static const std::string HTTP_PATCH;
|
||||
|
||||
|
||||
static const std::string HOST;
|
||||
static const std::string COOKIE;
|
||||
static const std::string AUTHORIZATION;
|
||||
@ -158,7 +170,7 @@ protected:
|
||||
///
|
||||
/// Throws a NotAuthenticatedException if no authentication information
|
||||
/// is contained in the request.
|
||||
|
||||
|
||||
void setCredentials(const std::string& header, const std::string& scheme, const std::string& authInfo);
|
||||
/// Writes the authentication scheme and information for
|
||||
/// this request to the given header.
|
||||
@ -170,12 +182,9 @@ private:
|
||||
MAX_URI_LENGTH = 16384,
|
||||
MAX_VERSION_LENGTH = 8
|
||||
};
|
||||
|
||||
|
||||
std::string _method;
|
||||
std::string _uri;
|
||||
|
||||
HTTPRequest(const HTTPRequest&);
|
||||
HTTPRequest& operator = (const HTTPRequest&);
|
||||
};
|
||||
|
||||
|
||||
|
@ -113,7 +113,7 @@ public:
|
||||
|
||||
HTTPResponse();
|
||||
/// Creates the HTTPResponse with OK status.
|
||||
|
||||
|
||||
HTTPResponse(HTTPStatus status, const std::string& reason);
|
||||
/// Creates the HTTPResponse with the given status
|
||||
/// and reason phrase.
|
||||
@ -121,41 +121,47 @@ public:
|
||||
HTTPResponse(const std::string& version, HTTPStatus status, const std::string& reason);
|
||||
/// Creates the HTTPResponse with the given version, status
|
||||
/// and reason phrase.
|
||||
|
||||
HTTPResponse(HTTPStatus status);
|
||||
|
||||
explicit HTTPResponse(HTTPStatus status);
|
||||
/// Creates the HTTPResponse with the given status
|
||||
/// an an appropriate reason phrase.
|
||||
/// and an appropriate reason phrase.
|
||||
|
||||
HTTPResponse(const std::string& version, HTTPStatus status);
|
||||
/// Creates the HTTPResponse with the given version, status
|
||||
/// an an appropriate reason phrase.
|
||||
/// and an appropriate reason phrase.
|
||||
|
||||
HTTPResponse(const HTTPResponse& other);
|
||||
/// Creates the HTTPResponse by copying another one.
|
||||
|
||||
virtual ~HTTPResponse();
|
||||
/// Destroys the HTTPResponse.
|
||||
|
||||
HTTPResponse& operator = (const HTTPResponse& other);
|
||||
/// Assignment operator.
|
||||
|
||||
void setStatus(HTTPStatus status);
|
||||
/// Sets the HTTP status code.
|
||||
///
|
||||
/// Does not change the reason phrase.
|
||||
|
||||
|
||||
HTTPStatus getStatus() const;
|
||||
/// Returns the HTTP status code.
|
||||
|
||||
|
||||
void setStatus(const std::string& status);
|
||||
/// Sets the HTTP status code.
|
||||
///
|
||||
/// The string must contain a valid
|
||||
/// HTTP numerical status code.
|
||||
|
||||
|
||||
void setReason(const std::string& reason);
|
||||
/// Sets the HTTP reason phrase.
|
||||
|
||||
|
||||
const std::string& getReason() const;
|
||||
/// Returns the HTTP reason phrase.
|
||||
|
||||
void setStatusAndReason(HTTPStatus status, const std::string& reason);
|
||||
/// Sets the HTTP status code and reason phrase.
|
||||
|
||||
|
||||
void setStatusAndReason(HTTPStatus status);
|
||||
/// Sets the HTTP status code and reason phrase.
|
||||
///
|
||||
@ -163,7 +169,7 @@ public:
|
||||
|
||||
void setDate(const Poco::Timestamp& dateTime);
|
||||
/// Sets the Date header to the given date/time value.
|
||||
|
||||
|
||||
Poco::Timestamp getDate() const;
|
||||
/// Returns the value of the Date header.
|
||||
|
||||
@ -187,7 +193,7 @@ public:
|
||||
/// given input stream.
|
||||
///
|
||||
/// 100 Continue responses are ignored.
|
||||
|
||||
|
||||
static const std::string& getReasonForStatus(HTTPStatus status);
|
||||
/// Returns an appropriate reason phrase
|
||||
/// for the given status code.
|
||||
@ -254,7 +260,7 @@ public:
|
||||
static const std::string HTTP_REASON_NOT_EXTENDED;
|
||||
static const std::string HTTP_REASON_NETWORK_AUTHENTICATION_REQUIRED;
|
||||
static const std::string HTTP_REASON_UNKNOWN;
|
||||
|
||||
|
||||
static const std::string DATE;
|
||||
static const std::string SET_COOKIE;
|
||||
|
||||
@ -265,12 +271,9 @@ private:
|
||||
MAX_STATUS_LENGTH = 3,
|
||||
MAX_REASON_LENGTH = 512
|
||||
};
|
||||
|
||||
|
||||
HTTPStatus _status;
|
||||
std::string _reason;
|
||||
|
||||
HTTPResponse(const HTTPResponse&);
|
||||
HTTPResponse& operator = (const HTTPResponse&);
|
||||
};
|
||||
|
||||
|
||||
|
171
Net/include/Poco/Net/NTLMCredentials.h
Normal file
171
Net/include/Poco/Net/NTLMCredentials.h
Normal file
@ -0,0 +1,171 @@
|
||||
//
|
||||
// NTLMCredentials.h
|
||||
//
|
||||
// Library: Net
|
||||
// Package: HTTP
|
||||
// Module: NTLMCredentials
|
||||
//
|
||||
// Definition of the NTLMCredentials class.
|
||||
//
|
||||
// Copyright (c) 2019, Applied Informatics Software Engineering GmbH.
|
||||
// and Contributors.
|
||||
//
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
//
|
||||
|
||||
|
||||
#ifndef Net_NTLMCredentials_INCLUDED
|
||||
#define Net_NTLMCredentials_INCLUDED
|
||||
|
||||
|
||||
#include "Poco/Net/Net.h"
|
||||
#include "Poco/BinaryReader.h"
|
||||
#include "Poco/BinaryWriter.h"
|
||||
#include <vector>
|
||||
|
||||
|
||||
namespace Poco {
|
||||
namespace Net {
|
||||
|
||||
|
||||
class Net_API NTLMCredentials
|
||||
/// This is a utility class for working with
|
||||
/// NTLMv2 Authentication.
|
||||
///
|
||||
/// Note: This implementation is based on the
|
||||
/// "The NTLM Authentication Protocol and Security Support Provider"
|
||||
/// document written by Eric Glass and avilable from
|
||||
/// http://davenport.sourceforge.net/ntlm.html
|
||||
/// and the NT LAN Manager (NTLM) Authentication Protocol
|
||||
/// [MS-NLMP] document by Microsoft.
|
||||
{
|
||||
public:
|
||||
enum
|
||||
{
|
||||
NTLM_MESSAGE_TYPE_NEGOTIATE = 0x01,
|
||||
NTLM_MESSAGE_TYPE_CHALLENGE = 0x02,
|
||||
NTLM_MESSAGE_TYPE_AUTHENTICATE = 0x03
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
NTLM_FLAG_NEGOTIATE_UNICODE = 0x00000001,
|
||||
NTLM_FLAG_NEGOTIATE_OEM = 0x00000002,
|
||||
NTLM_FLAG_REQUEST_TARGET = 0x00000004,
|
||||
NTLM_FLAG_NEGOTIATE_NTLM = 0x00000200,
|
||||
NTLM_FLAG_DOMAIN_SUPPLIED = 0x00001000,
|
||||
NTLM_FLAG_WORKST_SUPPLIED = 0x00002000,
|
||||
NTLM_FLAG_NEGOTIATE_LOCAL = 0x00004000,
|
||||
NTLM_FLAG_NEGOTIATE_ALWAYS_SIGN = 0x00008000,
|
||||
NTLM_FLAG_NEGOTIATE_NTLM2_KEY = 0x00080000,
|
||||
NTLM_FLAG_TARGET_DOMAIN = 0x00010000,
|
||||
NTLM_FLAG_TARGET_SERVER = 0x00020000,
|
||||
NTLM_FLAG_TARGET_SHARE = 0x00040000,
|
||||
NTLM_FLAG_NEGOTIATE_TARGET = 0x00800000,
|
||||
NTLM_FLAG_NEGOTIATE_128 = 0x20000000,
|
||||
NTLM_FLAG_NEGOTIATE_56 = 0x80000000
|
||||
};
|
||||
|
||||
struct NegotiateMessage
|
||||
/// This message is sent from the client to initiate NTLM authentication.
|
||||
{
|
||||
NegotiateMessage(): flags(0) {}
|
||||
|
||||
Poco::UInt32 flags;
|
||||
std::string domain;
|
||||
std::string workstation;
|
||||
};
|
||||
|
||||
struct ChallengeMessage
|
||||
/// This message is sent back by the server and contains the NTLM challenge.
|
||||
{
|
||||
ChallengeMessage(): flags(0) {}
|
||||
|
||||
Poco::UInt32 flags;
|
||||
std::vector<unsigned char> challenge;
|
||||
std::string target;
|
||||
std::vector<unsigned char> targetInfo;
|
||||
};
|
||||
|
||||
struct AuthenticateMessage
|
||||
/// This message is sent from the client to authenticate itself by providing
|
||||
/// a response to the server challenge.
|
||||
{
|
||||
AuthenticateMessage(): flags(0) {}
|
||||
|
||||
Poco::UInt32 flags;
|
||||
std::vector<unsigned char> lmResponse;
|
||||
std::vector<unsigned char> ntlmResponse;
|
||||
std::string target;
|
||||
std::string username;
|
||||
std::string workstation;
|
||||
};
|
||||
|
||||
struct BufferDesc
|
||||
{
|
||||
BufferDesc():
|
||||
length(0),
|
||||
reserved(0),
|
||||
offset(0)
|
||||
{
|
||||
}
|
||||
|
||||
BufferDesc(Poco::UInt16 len, Poco::UInt32 off):
|
||||
length(len),
|
||||
reserved(len),
|
||||
offset(off)
|
||||
{
|
||||
}
|
||||
|
||||
Poco::UInt16 length;
|
||||
Poco::UInt16 reserved;
|
||||
Poco::UInt32 offset;
|
||||
};
|
||||
|
||||
static std::vector<unsigned char> createNonce();
|
||||
/// Creates an 8-byte client nonce for NTLM authentication.
|
||||
|
||||
static Poco::UInt64 createTimestamp();
|
||||
/// Creates the NTLM timestamp in tenths of a microsecond since January 1, 1601,
|
||||
/// using the current system time.
|
||||
|
||||
static std::vector<unsigned char> createPasswordHash(const std::string& password);
|
||||
/// Creates the NTLM password hash (MD4 of UTF-16-converted password).
|
||||
|
||||
static std::vector<unsigned char> createNTLMv2Hash(const std::string& username, const std::string& target, const std::string& password);
|
||||
/// Creates the NTLMv2 hash, which is the HMAC-MD5 of the concatenated UTF-16 uppercase username and target,
|
||||
/// using the password hash as HMAC passphrase.
|
||||
|
||||
static std::vector<unsigned char> createLMv2Response(const std::vector<unsigned char>& ntlm2Hash, const std::vector<unsigned char>& challenge, const std::vector<unsigned char>& nonce);
|
||||
/// Creates the LMv2 response by computing the HMAC-MD5 of the challenge and nonce, using the
|
||||
/// ntlm2Hash (see createNTLMv2Hash()) as HMAC passphrase.
|
||||
|
||||
static std::vector<unsigned char> createNTLMv2Response(const std::vector<unsigned char>& ntlm2Hash, const std::vector<unsigned char>& challenge, const std::vector<unsigned char>& nonce, const std::vector<unsigned char>& targetInfo, Poco::UInt64 timestamp);
|
||||
/// Creates the NTLMv2 response by creating the "blob" and prepending its HMAC-MD5, using the ntlm2Hash as HMAC passphrase.
|
||||
|
||||
static std::vector<unsigned char> formatNegotiateMessage(const NegotiateMessage& message);
|
||||
/// Creates the NTLM Type 1 Negotiate message used for initiating NTLM authentication from the client.
|
||||
|
||||
static bool parseChallengeMessage(const unsigned char* buffer, std::size_t size, ChallengeMessage& message);
|
||||
/// Parses a NTLM Type 2 Challenge message.
|
||||
///
|
||||
/// Returns true if the message was parsed successfully, otherwise false.
|
||||
|
||||
static std::vector<unsigned char> formatAuthenticateMessage(const AuthenticateMessage& message);
|
||||
/// Creates the NTLM Type 1 Authenticate message used for initiating NTLM authentication from the client.
|
||||
|
||||
static void readBufferDesc(Poco::BinaryReader& reader, BufferDesc& desc);
|
||||
/// Reads a buffer descriptor.
|
||||
|
||||
static void writeBufferDesc(Poco::BinaryWriter& writer, const BufferDesc& desc);
|
||||
/// Writes a buffer descriptor.
|
||||
|
||||
static const std::string NTLMSSP;
|
||||
/// Message signature string.
|
||||
};
|
||||
|
||||
|
||||
} } // namespace Poco::Net
|
||||
|
||||
|
||||
#endif // Net_NTLMCredentials_INCLUDED
|
@ -13,13 +13,13 @@
|
||||
//
|
||||
|
||||
|
||||
#include "Poco/Exception.h"
|
||||
#include "Poco/Net/HTTPAuthenticationParams.h"
|
||||
#include "Poco/Net/HTTPRequest.h"
|
||||
#include "Poco/Net/HTTPResponse.h"
|
||||
#include "Poco/Net/NetException.h"
|
||||
#include "Poco/String.h"
|
||||
#include "Poco/Ascii.h"
|
||||
#include "Poco/Exception.h"
|
||||
|
||||
|
||||
using Poco::icompare;
|
||||
@ -66,6 +66,7 @@ namespace Net {
|
||||
|
||||
|
||||
const std::string HTTPAuthenticationParams::REALM("realm");
|
||||
const std::string HTTPAuthenticationParams::NTLM("NTLM");
|
||||
const std::string HTTPAuthenticationParams::WWW_AUTHENTICATE("WWW-Authenticate");
|
||||
const std::string HTTPAuthenticationParams::PROXY_AUTHENTICATE("Proxy-Authenticate");
|
||||
|
||||
@ -135,20 +136,25 @@ void HTTPAuthenticationParams::fromResponse(const HTTPResponse& response, const
|
||||
bool found = false;
|
||||
while (!found && it != response.end() && icompare(it->first, header) == 0)
|
||||
{
|
||||
const std::string& header = it->second;
|
||||
if (icompare(header, 0, 6, "Basic ") == 0)
|
||||
const std::string& headerValue = it->second;
|
||||
if (icompare(headerValue, 0, 6, "Basic ") == 0)
|
||||
{
|
||||
parse(header.begin() + 6, header.end());
|
||||
parse(headerValue.begin() + 6, headerValue.end());
|
||||
found = true;
|
||||
}
|
||||
else if (icompare(header, 0, 7, "Digest ") == 0)
|
||||
else if (icompare(headerValue, 0, 7, "Digest ") == 0)
|
||||
{
|
||||
parse(header.begin() + 7, header.end());
|
||||
parse(headerValue.begin() + 7, headerValue.end());
|
||||
found = true;
|
||||
}
|
||||
else if (icompare(headerValue, 0, 5, "NTLM ") == 0)
|
||||
{
|
||||
set(NTLM, headerValue.substr(5));
|
||||
found = true;
|
||||
}
|
||||
++it;
|
||||
}
|
||||
if (!found) throw NotAuthenticatedException("No Basic or Digest authentication header found");
|
||||
if (!found) throw NotAuthenticatedException("No Basic, Digest or NTLM authentication header found");
|
||||
}
|
||||
|
||||
|
||||
@ -166,21 +172,27 @@ void HTTPAuthenticationParams::setRealm(const std::string& realm)
|
||||
|
||||
std::string HTTPAuthenticationParams::toString() const
|
||||
{
|
||||
ConstIterator iter = begin();
|
||||
std::string result;
|
||||
|
||||
if (iter != end())
|
||||
if (size() == 1 && find(NTLM) != end())
|
||||
{
|
||||
formatParameter(result, iter->first, iter->second);
|
||||
++iter;
|
||||
result = get(NTLM);
|
||||
}
|
||||
|
||||
for (; iter != end(); ++iter)
|
||||
else
|
||||
{
|
||||
result.append(", ");
|
||||
formatParameter(result, iter->first, iter->second);
|
||||
}
|
||||
ConstIterator iter = begin();
|
||||
|
||||
if (iter != end())
|
||||
{
|
||||
formatParameter(result, iter->first, iter->second);
|
||||
++iter;
|
||||
}
|
||||
|
||||
for (; iter != end(); ++iter)
|
||||
{
|
||||
result.append(", ");
|
||||
formatParameter(result, iter->first, iter->second);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -19,7 +19,7 @@
|
||||
#include "Poco/Net/HTTPStream.h"
|
||||
#include "Poco/Net/HTTPFixedLengthStream.h"
|
||||
#include "Poco/Net/HTTPChunkedStream.h"
|
||||
#include "Poco/Net/HTTPBasicCredentials.h"
|
||||
#include "Poco/Net/HTTPCredentials.h"
|
||||
#include "Poco/Net/NetException.h"
|
||||
#include "Poco/NumberFormatter.h"
|
||||
#include "Poco/CountingStream.h"
|
||||
@ -45,7 +45,8 @@ HTTPClientSession::HTTPClientSession():
|
||||
_reconnect(false),
|
||||
_mustReconnect(false),
|
||||
_expectResponseBody(false),
|
||||
_responseReceived(false)
|
||||
_responseReceived(false),
|
||||
_ntlmProxyAuthenticated(false)
|
||||
{
|
||||
}
|
||||
|
||||
@ -58,7 +59,8 @@ HTTPClientSession::HTTPClientSession(const StreamSocket& socket):
|
||||
_reconnect(false),
|
||||
_mustReconnect(false),
|
||||
_expectResponseBody(false),
|
||||
_responseReceived(false)
|
||||
_responseReceived(false),
|
||||
_ntlmProxyAuthenticated(false)
|
||||
{
|
||||
}
|
||||
|
||||
@ -71,7 +73,8 @@ HTTPClientSession::HTTPClientSession(const SocketAddress& address):
|
||||
_reconnect(false),
|
||||
_mustReconnect(false),
|
||||
_expectResponseBody(false),
|
||||
_responseReceived(false)
|
||||
_responseReceived(false),
|
||||
_ntlmProxyAuthenticated(false)
|
||||
{
|
||||
}
|
||||
|
||||
@ -84,7 +87,8 @@ HTTPClientSession::HTTPClientSession(const std::string& host, Poco::UInt16 port)
|
||||
_reconnect(false),
|
||||
_mustReconnect(false),
|
||||
_expectResponseBody(false),
|
||||
_responseReceived(false)
|
||||
_responseReceived(false),
|
||||
_ntlmProxyAuthenticated(false)
|
||||
{
|
||||
}
|
||||
|
||||
@ -97,7 +101,8 @@ HTTPClientSession::HTTPClientSession(const std::string& host, Poco::UInt16 port,
|
||||
_reconnect(false),
|
||||
_mustReconnect(false),
|
||||
_expectResponseBody(false),
|
||||
_responseReceived(false)
|
||||
_responseReceived(false),
|
||||
_ntlmProxyAuthenticated(false)
|
||||
{
|
||||
}
|
||||
|
||||
@ -195,8 +200,6 @@ std::ostream& HTTPClientSession::sendRequest(HTTPRequest& request)
|
||||
{
|
||||
_pRequestStream = 0;
|
||||
_pResponseStream = 0;
|
||||
clearException();
|
||||
_responseReceived = false;
|
||||
|
||||
bool keepAlive = getKeepAlive();
|
||||
if (((connected() && !keepAlive) || mustReconnect()) && !_host.empty())
|
||||
@ -207,50 +210,28 @@ std::ostream& HTTPClientSession::sendRequest(HTTPRequest& request)
|
||||
try
|
||||
{
|
||||
if (!connected())
|
||||
{
|
||||
_ntlmProxyAuthenticated = false;
|
||||
reconnect();
|
||||
}
|
||||
if (!keepAlive)
|
||||
{
|
||||
request.setKeepAlive(false);
|
||||
}
|
||||
if (!request.has(HTTPRequest::HOST) && !_host.empty())
|
||||
{
|
||||
request.setHost(_host, _port);
|
||||
}
|
||||
if (!_proxyConfig.host.empty() && !bypassProxy())
|
||||
{
|
||||
request.setURI(proxyRequestPrefix() + request.getURI());
|
||||
std::string prefix = proxyRequestPrefix();
|
||||
if (!prefix.empty() && request.getURI().compare(0, 7, "http://") != 0 && request.getURI().compare(0, 8, "https://") != 0)
|
||||
request.setURI(prefix + request.getURI());
|
||||
if (keepAlive) request.set(HTTPMessage::PROXY_CONNECTION, HTTPMessage::CONNECTION_KEEP_ALIVE);
|
||||
proxyAuthenticate(request);
|
||||
}
|
||||
_reconnect = keepAlive;
|
||||
_expectResponseBody = request.getMethod() != HTTPRequest::HTTP_HEAD;
|
||||
const std::string& method = request.getMethod();
|
||||
if (request.getChunkedTransferEncoding())
|
||||
{
|
||||
HTTPHeaderOutputStream hos(*this);
|
||||
request.write(hos);
|
||||
_pRequestStream = new HTTPChunkedOutputStream(*this);
|
||||
}
|
||||
else if (request.hasContentLength())
|
||||
{
|
||||
Poco::CountingOutputStream cs;
|
||||
request.write(cs);
|
||||
#if POCO_HAVE_INT64
|
||||
_pRequestStream = new HTTPFixedLengthOutputStream(*this, request.getContentLength64() + cs.chars());
|
||||
#else
|
||||
_pRequestStream = new HTTPFixedLengthOutputStream(*this, request.getContentLength() + cs.chars());
|
||||
#endif
|
||||
request.write(*_pRequestStream);
|
||||
}
|
||||
else if ((method != HTTPRequest::HTTP_PUT && method != HTTPRequest::HTTP_POST && method != HTTPRequest::HTTP_PATCH) || request.has(HTTPRequest::UPGRADE))
|
||||
{
|
||||
Poco::CountingOutputStream cs;
|
||||
request.write(cs);
|
||||
_pRequestStream = new HTTPFixedLengthOutputStream(*this, cs.chars());
|
||||
request.write(*_pRequestStream);
|
||||
}
|
||||
else
|
||||
{
|
||||
_pRequestStream = new HTTPOutputStream(*this);
|
||||
request.write(*_pRequestStream);
|
||||
}
|
||||
_lastRequest.update();
|
||||
return *_pRequestStream;
|
||||
return sendRequestImpl(request);
|
||||
}
|
||||
catch (Exception&)
|
||||
{
|
||||
@ -260,6 +241,48 @@ std::ostream& HTTPClientSession::sendRequest(HTTPRequest& request)
|
||||
}
|
||||
|
||||
|
||||
std::ostream& HTTPClientSession::sendRequestImpl(const HTTPRequest& request)
|
||||
{
|
||||
_pRequestStream = 0;
|
||||
_pResponseStream = 0;
|
||||
clearException();
|
||||
_responseReceived = false;
|
||||
_expectResponseBody = request.getMethod() != HTTPRequest::HTTP_HEAD;
|
||||
const std::string& method = request.getMethod();
|
||||
if (request.getChunkedTransferEncoding())
|
||||
{
|
||||
HTTPHeaderOutputStream hos(*this);
|
||||
request.write(hos);
|
||||
_pRequestStream = new HTTPChunkedOutputStream(*this);
|
||||
}
|
||||
else if (request.hasContentLength())
|
||||
{
|
||||
Poco::CountingOutputStream cs;
|
||||
request.write(cs);
|
||||
#if POCO_HAVE_INT64
|
||||
_pRequestStream = new HTTPFixedLengthOutputStream(*this, request.getContentLength64() + cs.chars());
|
||||
#else
|
||||
_pRequestStream = new HTTPFixedLengthOutputStream(*this, request.getContentLength() + cs.chars());
|
||||
#endif
|
||||
request.write(*_pRequestStream);
|
||||
}
|
||||
else if ((method != HTTPRequest::HTTP_PUT && method != HTTPRequest::HTTP_POST && method != HTTPRequest::HTTP_PATCH) || request.has(HTTPRequest::UPGRADE))
|
||||
{
|
||||
Poco::CountingOutputStream cs;
|
||||
request.write(cs);
|
||||
_pRequestStream = new HTTPFixedLengthOutputStream(*this, cs.chars());
|
||||
request.write(*_pRequestStream);
|
||||
}
|
||||
else
|
||||
{
|
||||
_pRequestStream = new HTTPOutputStream(*this);
|
||||
request.write(*_pRequestStream);
|
||||
}
|
||||
_lastRequest.update();
|
||||
return *_pRequestStream;
|
||||
}
|
||||
|
||||
|
||||
std::istream& HTTPClientSession::receiveResponse(HTTPResponse& response)
|
||||
{
|
||||
_pRequestStream = 0;
|
||||
@ -409,20 +432,89 @@ bool HTTPClientSession::mustReconnect() const
|
||||
|
||||
void HTTPClientSession::proxyAuthenticate(HTTPRequest& request)
|
||||
{
|
||||
proxyAuthenticateImpl(request);
|
||||
proxyAuthenticateImpl(request, _proxyConfig);
|
||||
}
|
||||
|
||||
|
||||
void HTTPClientSession::proxyAuthenticateImpl(HTTPRequest& request)
|
||||
void HTTPClientSession::proxyAuthenticateImpl(HTTPRequest& request, const ProxyConfig& proxyConfig)
|
||||
{
|
||||
if (!_proxyConfig.username.empty())
|
||||
switch (proxyConfig.authMethod)
|
||||
{
|
||||
HTTPBasicCredentials creds(_proxyConfig.username, _proxyConfig.password);
|
||||
creds.proxyAuthenticate(request);
|
||||
case PROXY_AUTH_NONE:
|
||||
break;
|
||||
|
||||
case PROXY_AUTH_HTTP_BASIC:
|
||||
_proxyBasicCreds.setUsername(proxyConfig.username);
|
||||
_proxyBasicCreds.setPassword(proxyConfig.password);
|
||||
_proxyBasicCreds.proxyAuthenticate(request);
|
||||
break;
|
||||
|
||||
case PROXY_AUTH_HTTP_DIGEST:
|
||||
if (HTTPCredentials::hasDigestCredentials(request))
|
||||
{
|
||||
_proxyDigestCreds.updateProxyAuthInfo(request);
|
||||
}
|
||||
else
|
||||
{
|
||||
_proxyDigestCreds.setUsername(proxyConfig.username);
|
||||
_proxyDigestCreds.setPassword(proxyConfig.password);
|
||||
proxyAuthenticateDigest(request);
|
||||
}
|
||||
|
||||
case PROXY_AUTH_NTLM:
|
||||
if (_ntlmProxyAuthenticated)
|
||||
{
|
||||
_proxyNTLMCreds.updateProxyAuthInfo(request);
|
||||
}
|
||||
else
|
||||
{
|
||||
_proxyNTLMCreds.setUsername(proxyConfig.username);
|
||||
_proxyNTLMCreds.setPassword(proxyConfig.password);
|
||||
proxyAuthenticateNTLM(request);
|
||||
_ntlmProxyAuthenticated = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void HTTPClientSession::proxyAuthenticateDigest(HTTPRequest& request)
|
||||
{
|
||||
HTTPResponse response;
|
||||
request.set(HTTPMessage::PROXY_CONNECTION, HTTPMessage::CONNECTION_KEEP_ALIVE);
|
||||
sendChallengeRequest(request, response);
|
||||
_proxyDigestCreds.proxyAuthenticate(request, response);
|
||||
}
|
||||
|
||||
|
||||
void HTTPClientSession::proxyAuthenticateNTLM(HTTPRequest& request)
|
||||
{
|
||||
HTTPResponse response;
|
||||
request.set(HTTPMessage::PROXY_CONNECTION, HTTPMessage::CONNECTION_KEEP_ALIVE);
|
||||
_proxyNTLMCreds.proxyAuthenticate(request, std::string());
|
||||
sendChallengeRequest(request, response);
|
||||
_proxyNTLMCreds.proxyAuthenticate(request, response);
|
||||
}
|
||||
|
||||
|
||||
void HTTPClientSession::sendChallengeRequest(const HTTPRequest& request, HTTPResponse& response)
|
||||
{
|
||||
if (!connected())
|
||||
{
|
||||
reconnect();
|
||||
}
|
||||
|
||||
HTTPRequest challengeRequest(request);
|
||||
if (challengeRequest.hasContentLength())
|
||||
{
|
||||
challengeRequest.setContentLength(0);
|
||||
}
|
||||
|
||||
sendRequestImpl(challengeRequest);
|
||||
std::istream& istr = receiveResponse(response);
|
||||
while (istr.good()) istr.get();
|
||||
}
|
||||
|
||||
|
||||
StreamSocket HTTPClientSession::proxyConnect()
|
||||
{
|
||||
ProxyConfig emptyProxyConfig;
|
||||
@ -433,9 +525,9 @@ StreamSocket HTTPClientSession::proxyConnect()
|
||||
NumberFormatter::append(targetAddress, _port);
|
||||
HTTPRequest proxyRequest(HTTPRequest::HTTP_CONNECT, targetAddress, HTTPMessage::HTTP_1_1);
|
||||
HTTPResponse proxyResponse;
|
||||
proxyRequest.set("Proxy-Connection", "keep-alive");
|
||||
proxyRequest.set("Host", getHost());
|
||||
proxyAuthenticateImpl(proxyRequest);
|
||||
proxyRequest.set(HTTPMessage::PROXY_CONNECTION, HTTPMessage::CONNECTION_KEEP_ALIVE);
|
||||
proxyRequest.set(HTTPRequest::HOST, getHost());
|
||||
proxySession.proxyAuthenticateImpl(proxyRequest, _proxyConfig);
|
||||
proxySession.setKeepAlive(true);
|
||||
proxySession.sendRequest(proxyRequest);
|
||||
proxySession.receiveResponse(proxyResponse);
|
||||
|
@ -75,34 +75,45 @@ void HTTPCredentials::authenticate(HTTPRequest& request, const HTTPResponse& res
|
||||
{
|
||||
for (HTTPResponse::ConstIterator iter = response.find(HTTPAuthenticationParams::WWW_AUTHENTICATE); iter != response.end(); ++iter)
|
||||
{
|
||||
if (isBasicCredentials(iter->second))
|
||||
if (isBasicCredentials(iter->second))
|
||||
{
|
||||
HTTPBasicCredentials(_digest.getUsername(), _digest.getPassword()).authenticate(request);
|
||||
return;
|
||||
}
|
||||
else if (isDigestCredentials(iter->second))
|
||||
}
|
||||
else if (isDigestCredentials(iter->second))
|
||||
{
|
||||
_digest.authenticate(request, HTTPAuthenticationParams(iter->second.substr(7)));
|
||||
return;
|
||||
}
|
||||
else if (isNTLMCredentials(iter->second))
|
||||
{
|
||||
_ntlm.setUsername(_digest.getUsername());
|
||||
_ntlm.setPassword(_digest.getPassword());
|
||||
_ntlm.authenticate(request, iter->second.substr(5));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void HTTPCredentials::updateAuthInfo(HTTPRequest& request)
|
||||
{
|
||||
if (request.has(HTTPRequest::AUTHORIZATION))
|
||||
if (request.has(HTTPRequest::AUTHORIZATION))
|
||||
{
|
||||
const std::string& authorization = request.get(HTTPRequest::AUTHORIZATION);
|
||||
|
||||
if (isBasicCredentials(authorization))
|
||||
if (isBasicCredentials(authorization))
|
||||
{
|
||||
HTTPBasicCredentials(_digest.getUsername(), _digest.getPassword()).authenticate(request);
|
||||
}
|
||||
else if (isDigestCredentials(authorization))
|
||||
}
|
||||
else if (isDigestCredentials(authorization))
|
||||
{
|
||||
_digest.updateAuthInfo(request);
|
||||
}
|
||||
else if (isNTLMCredentials(authorization))
|
||||
{
|
||||
_ntlm.updateAuthInfo(request);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -111,34 +122,45 @@ void HTTPCredentials::proxyAuthenticate(HTTPRequest& request, const HTTPResponse
|
||||
{
|
||||
for (HTTPResponse::ConstIterator iter = response.find(HTTPAuthenticationParams::PROXY_AUTHENTICATE); iter != response.end(); ++iter)
|
||||
{
|
||||
if (isBasicCredentials(iter->second))
|
||||
if (isBasicCredentials(iter->second))
|
||||
{
|
||||
HTTPBasicCredentials(_digest.getUsername(), _digest.getPassword()).proxyAuthenticate(request);
|
||||
return;
|
||||
}
|
||||
else if (isDigestCredentials(iter->second))
|
||||
}
|
||||
else if (isDigestCredentials(iter->second))
|
||||
{
|
||||
_digest.proxyAuthenticate(request, HTTPAuthenticationParams(iter->second.substr(7)));
|
||||
return;
|
||||
}
|
||||
else if (isNTLMCredentials(iter->second))
|
||||
{
|
||||
_ntlm.setUsername(_digest.getUsername());
|
||||
_ntlm.setPassword(_digest.getPassword());
|
||||
_ntlm.proxyAuthenticate(request, iter->second.substr(5));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void HTTPCredentials::updateProxyAuthInfo(HTTPRequest& request)
|
||||
{
|
||||
if (request.has(HTTPRequest::PROXY_AUTHORIZATION))
|
||||
if (request.has(HTTPRequest::PROXY_AUTHORIZATION))
|
||||
{
|
||||
const std::string& authorization = request.get(HTTPRequest::PROXY_AUTHORIZATION);
|
||||
|
||||
if (isBasicCredentials(authorization))
|
||||
if (isBasicCredentials(authorization))
|
||||
{
|
||||
HTTPBasicCredentials(_digest.getUsername(), _digest.getPassword()).proxyAuthenticate(request);
|
||||
}
|
||||
else if (isDigestCredentials(authorization))
|
||||
}
|
||||
else if (isDigestCredentials(authorization))
|
||||
{
|
||||
_digest.updateProxyAuthInfo(request);
|
||||
}
|
||||
else if (isNTLMCredentials(authorization))
|
||||
{
|
||||
_ntlm.updateProxyAuthInfo(request);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -155,6 +177,12 @@ bool HTTPCredentials::isDigestCredentials(const std::string& header)
|
||||
}
|
||||
|
||||
|
||||
bool HTTPCredentials::isNTLMCredentials(const std::string& header)
|
||||
{
|
||||
return icompare(header, 0, 4, "NTLM") == 0 && (header.size() > 5 ? Poco::Ascii::isSpace(header[5]) : true);
|
||||
}
|
||||
|
||||
|
||||
bool HTTPCredentials::hasBasicCredentials(const HTTPRequest& request)
|
||||
{
|
||||
return request.has(HTTPRequest::AUTHORIZATION) && isBasicCredentials(request.get(HTTPRequest::AUTHORIZATION));
|
||||
@ -167,6 +195,12 @@ bool HTTPCredentials::hasDigestCredentials(const HTTPRequest& request)
|
||||
}
|
||||
|
||||
|
||||
bool HTTPCredentials::hasNTLMCredentials(const HTTPRequest& request)
|
||||
{
|
||||
return request.has(HTTPRequest::AUTHORIZATION) && isNTLMCredentials(request.get(HTTPRequest::AUTHORIZATION));
|
||||
}
|
||||
|
||||
|
||||
bool HTTPCredentials::hasProxyBasicCredentials(const HTTPRequest& request)
|
||||
{
|
||||
return request.has(HTTPRequest::PROXY_AUTHORIZATION) && isBasicCredentials(request.get(HTTPRequest::PROXY_AUTHORIZATION));
|
||||
@ -179,16 +213,22 @@ bool HTTPCredentials::hasProxyDigestCredentials(const HTTPRequest& request)
|
||||
}
|
||||
|
||||
|
||||
bool HTTPCredentials::hasProxyNTLMCredentials(const HTTPRequest& request)
|
||||
{
|
||||
return request.has(HTTPRequest::PROXY_AUTHORIZATION) && isNTLMCredentials(request.get(HTTPRequest::PROXY_AUTHORIZATION));
|
||||
}
|
||||
|
||||
|
||||
void HTTPCredentials::extractCredentials(const std::string& userInfo, std::string& username, std::string& password)
|
||||
{
|
||||
const std::string::size_type p = userInfo.find(':');
|
||||
|
||||
if (p != std::string::npos)
|
||||
if (p != std::string::npos)
|
||||
{
|
||||
username.assign(userInfo, 0, p);
|
||||
password.assign(userInfo, p + 1, std::string::npos);
|
||||
}
|
||||
else
|
||||
}
|
||||
else
|
||||
{
|
||||
username.assign(userInfo);
|
||||
password.clear();
|
||||
@ -198,7 +238,7 @@ void HTTPCredentials::extractCredentials(const std::string& userInfo, std::strin
|
||||
|
||||
void HTTPCredentials::extractCredentials(const Poco::URI& uri, std::string& username, std::string& password)
|
||||
{
|
||||
if (!uri.getUserInfo().empty())
|
||||
if (!uri.getUserInfo().empty())
|
||||
{
|
||||
extractCredentials(uri.getUserInfo(), username, password);
|
||||
}
|
||||
|
@ -38,6 +38,7 @@ const std::string HTTPMessage::CONTENT_LENGTH = "Content-Length";
|
||||
const std::string HTTPMessage::CONTENT_TYPE = "Content-Type";
|
||||
const std::string HTTPMessage::TRANSFER_ENCODING = "Transfer-Encoding";
|
||||
const std::string HTTPMessage::CONNECTION = "Connection";
|
||||
const std::string HTTPMessage::PROXY_CONNECTION = "Proxy-Connection";
|
||||
const std::string HTTPMessage::CONNECTION_KEEP_ALIVE = "Keep-Alive";
|
||||
const std::string HTTPMessage::CONNECTION_CLOSE = "Close";
|
||||
const std::string HTTPMessage::EMPTY;
|
||||
@ -55,11 +56,29 @@ HTTPMessage::HTTPMessage(const std::string& version):
|
||||
}
|
||||
|
||||
|
||||
HTTPMessage::HTTPMessage(const HTTPMessage& other):
|
||||
MessageHeader(other),
|
||||
_version(other._version)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
HTTPMessage::~HTTPMessage()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
HTTPMessage& HTTPMessage::operator = (const HTTPMessage& other)
|
||||
{
|
||||
if (this != &other)
|
||||
{
|
||||
MessageHeader::operator = (other);
|
||||
_version = other._version;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
void HTTPMessage::setVersion(const std::string& version)
|
||||
{
|
||||
_version = version;
|
||||
@ -74,7 +93,7 @@ void HTTPMessage::setContentLength(std::streamsize length)
|
||||
erase(CONTENT_LENGTH);
|
||||
}
|
||||
|
||||
|
||||
|
||||
std::streamsize HTTPMessage::getContentLength() const
|
||||
{
|
||||
const std::string& contentLength = get(CONTENT_LENGTH, EMPTY);
|
||||
@ -89,7 +108,7 @@ std::streamsize HTTPMessage::getContentLength() const
|
||||
}
|
||||
|
||||
|
||||
#if defined(POCO_HAVE_INT64)
|
||||
#if defined(POCO_HAVE_INT64)
|
||||
void HTTPMessage::setContentLength64(Poco::Int64 length)
|
||||
{
|
||||
if (length != UNKNOWN_CONTENT_LENGTH)
|
||||
@ -98,7 +117,7 @@ void HTTPMessage::setContentLength64(Poco::Int64 length)
|
||||
erase(CONTENT_LENGTH);
|
||||
}
|
||||
|
||||
|
||||
|
||||
Poco::Int64 HTTPMessage::getContentLength64() const
|
||||
{
|
||||
const std::string& contentLength = get(CONTENT_LENGTH, EMPTY);
|
||||
@ -108,7 +127,7 @@ Poco::Int64 HTTPMessage::getContentLength64() const
|
||||
}
|
||||
else return UNKNOWN_CONTENT_LENGTH;
|
||||
}
|
||||
#endif // defined(POCO_HAVE_INT64)
|
||||
#endif // defined(POCO_HAVE_INT64)
|
||||
|
||||
|
||||
void HTTPMessage::setTransferEncoding(const std::string& transferEncoding)
|
||||
@ -134,13 +153,13 @@ void HTTPMessage::setChunkedTransferEncoding(bool flag)
|
||||
setTransferEncoding(IDENTITY_TRANSFER_ENCODING);
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool HTTPMessage::getChunkedTransferEncoding() const
|
||||
{
|
||||
return icompare(getTransferEncoding(), CHUNKED_TRANSFER_ENCODING) == 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void HTTPMessage::setContentType(const std::string& mediaType)
|
||||
{
|
||||
if (mediaType.empty())
|
||||
@ -155,7 +174,7 @@ void HTTPMessage::setContentType(const MediaType& mediaType)
|
||||
setContentType(mediaType.toString());
|
||||
}
|
||||
|
||||
|
||||
|
||||
const std::string& HTTPMessage::getContentType() const
|
||||
{
|
||||
return get(CONTENT_TYPE, UNKNOWN_CONTENT_TYPE);
|
||||
|
190
Net/src/HTTPNTLMCredentials.cpp
Normal file
190
Net/src/HTTPNTLMCredentials.cpp
Normal file
@ -0,0 +1,190 @@
|
||||
//
|
||||
// HTTPNTLMCredentials.cpp
|
||||
//
|
||||
// Library: Net
|
||||
// Package: HTTP
|
||||
// Module: HTTPNTLMCredentials
|
||||
//
|
||||
// Copyright (c) 2019, Applied Informatics Software Engineering GmbH.
|
||||
// and Contributors.
|
||||
//
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
//
|
||||
|
||||
|
||||
#include "Poco/Net/HTTPNTLMCredentials.h"
|
||||
#include "Poco/Net/NTLMCredentials.h"
|
||||
#include "Poco/Net/HTTPAuthenticationParams.h"
|
||||
#include "Poco/Net/HTTPRequest.h"
|
||||
#include "Poco/Net/HTTPResponse.h"
|
||||
#include "Poco/DateTime.h"
|
||||
#include "Poco/NumberFormatter.h"
|
||||
#include "Poco/Exception.h"
|
||||
#include "Poco/Base64Encoder.h"
|
||||
#include "Poco/Base64Decoder.h"
|
||||
#include "Poco/MemoryStream.h"
|
||||
#include <sstream>
|
||||
|
||||
|
||||
namespace Poco {
|
||||
namespace Net {
|
||||
|
||||
|
||||
const std::string HTTPNTLMCredentials::SCHEME = "NTLM";
|
||||
|
||||
|
||||
HTTPNTLMCredentials::HTTPNTLMCredentials()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
HTTPNTLMCredentials::HTTPNTLMCredentials(const std::string& username, const std::string& password):
|
||||
_username(username),
|
||||
_password(password)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
HTTPNTLMCredentials::~HTTPNTLMCredentials()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void HTTPNTLMCredentials::reset()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void HTTPNTLMCredentials::setUsername(const std::string& username)
|
||||
{
|
||||
_username = username;
|
||||
}
|
||||
|
||||
|
||||
void HTTPNTLMCredentials::setPassword(const std::string& password)
|
||||
{
|
||||
_password = password;
|
||||
}
|
||||
|
||||
|
||||
void HTTPNTLMCredentials::authenticate(HTTPRequest& request, const HTTPResponse& response)
|
||||
{
|
||||
HTTPAuthenticationParams params(response);
|
||||
authenticate(request, params.get(HTTPAuthenticationParams::NTLM, ""));
|
||||
}
|
||||
|
||||
|
||||
void HTTPNTLMCredentials::authenticate(HTTPRequest& request, const std::string& ntlmChallengeBase64)
|
||||
{
|
||||
std::string ntlmMessage = createNTLMMessage(ntlmChallengeBase64);
|
||||
request.setCredentials(SCHEME, ntlmMessage);
|
||||
}
|
||||
|
||||
|
||||
void HTTPNTLMCredentials::updateAuthInfo(HTTPRequest& request)
|
||||
{
|
||||
request.removeCredentials();
|
||||
}
|
||||
|
||||
|
||||
void HTTPNTLMCredentials::proxyAuthenticate(HTTPRequest& request, const HTTPResponse& response)
|
||||
{
|
||||
HTTPAuthenticationParams params(response, HTTPAuthenticationParams::PROXY_AUTHENTICATE);
|
||||
proxyAuthenticate(request, params.get(HTTPAuthenticationParams::NTLM, ""));
|
||||
}
|
||||
|
||||
|
||||
void HTTPNTLMCredentials::proxyAuthenticate(HTTPRequest& request, const std::string& ntlmChallengeBase64)
|
||||
{
|
||||
std::string ntlmMessage = createNTLMMessage(ntlmChallengeBase64);
|
||||
request.setProxyCredentials(SCHEME, ntlmMessage);
|
||||
}
|
||||
|
||||
|
||||
void HTTPNTLMCredentials::updateProxyAuthInfo(HTTPRequest& request)
|
||||
{
|
||||
request.removeProxyCredentials();
|
||||
}
|
||||
|
||||
|
||||
std::string HTTPNTLMCredentials::createNTLMMessage(const std::string& responseAuthParams)
|
||||
{
|
||||
if (responseAuthParams.empty())
|
||||
{
|
||||
NTLMCredentials::NegotiateMessage negotiateMsg;
|
||||
std::string username;
|
||||
splitUsername(_username, username, negotiateMsg.domain);
|
||||
std::vector<unsigned char> negotiateBuf = NTLMCredentials::formatNegotiateMessage(negotiateMsg);
|
||||
|
||||
std::ostringstream ostr;
|
||||
Poco::Base64Encoder base64(ostr);
|
||||
base64.rdbuf()->setLineLength(0);
|
||||
base64.write(reinterpret_cast<const char*>(&negotiateBuf[0]), negotiateBuf.size());
|
||||
base64.close();
|
||||
return ostr.str();
|
||||
}
|
||||
else
|
||||
{
|
||||
Poco::MemoryInputStream istr(responseAuthParams.data(), responseAuthParams.size());
|
||||
Poco::Base64Decoder debase64(istr);
|
||||
std::vector<unsigned char> buffer(responseAuthParams.size());
|
||||
debase64.read(reinterpret_cast<char*>(&buffer[0]), buffer.size());
|
||||
std::size_t size = debase64.gcount();
|
||||
|
||||
Poco::Net::NTLMCredentials::ChallengeMessage challengeMsg;
|
||||
if (NTLMCredentials::parseChallengeMessage(&buffer[0], size, challengeMsg))
|
||||
{
|
||||
std::string username;
|
||||
std::string domain;
|
||||
splitUsername(_username, username, domain);
|
||||
|
||||
NTLMCredentials::AuthenticateMessage authenticateMsg;
|
||||
authenticateMsg.flags = challengeMsg.flags;
|
||||
authenticateMsg.target = challengeMsg.target;
|
||||
authenticateMsg.username = username;
|
||||
|
||||
std::vector<unsigned char> nonce = NTLMCredentials::createNonce();
|
||||
Poco::UInt64 timestamp = NTLMCredentials::createTimestamp();
|
||||
std::vector<unsigned char> ntlm2Hash = NTLMCredentials::createNTLMv2Hash(username, challengeMsg.target, _password);
|
||||
authenticateMsg.lmResponse = NTLMCredentials::createLMv2Response(ntlm2Hash, challengeMsg.challenge, nonce);
|
||||
authenticateMsg.ntlmResponse = Poco::Net::NTLMCredentials::createNTLMv2Response(ntlm2Hash, challengeMsg.challenge, nonce, challengeMsg.targetInfo, timestamp);
|
||||
|
||||
std::vector<unsigned char> authenticateBuf = Poco::Net::NTLMCredentials::formatAuthenticateMessage(authenticateMsg);
|
||||
|
||||
std::ostringstream ostr;
|
||||
Poco::Base64Encoder base64(ostr);
|
||||
base64.rdbuf()->setLineLength(0);
|
||||
base64.write(reinterpret_cast<const char*>(&authenticateBuf[0]), authenticateBuf.size());
|
||||
base64.close();
|
||||
return ostr.str();
|
||||
}
|
||||
else throw Poco::InvalidArgumentException("Invalid NTLM challenge");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void HTTPNTLMCredentials::splitUsername(const std::string& usernameAndDomain, std::string& username, std::string& domain)
|
||||
{
|
||||
std::string::size_type pos = usernameAndDomain.find('\\');
|
||||
if (pos != std::string::npos)
|
||||
{
|
||||
domain.assign(usernameAndDomain, 0, pos);
|
||||
username.assign(usernameAndDomain, pos + 1);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
pos = usernameAndDomain.find('@');
|
||||
if (pos != std::string::npos)
|
||||
{
|
||||
username.assign(usernameAndDomain, 0, pos);
|
||||
domain.assign(usernameAndDomain, pos + 1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
username = usernameAndDomain;
|
||||
}
|
||||
|
||||
|
||||
|
||||
} } // namespace Poco::Net
|
@ -50,7 +50,7 @@ HTTPRequest::HTTPRequest():
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
HTTPRequest::HTTPRequest(const std::string& version):
|
||||
HTTPMessage(version),
|
||||
_method(HTTP_GET),
|
||||
@ -58,7 +58,7 @@ HTTPRequest::HTTPRequest(const std::string& version):
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
HTTPRequest::HTTPRequest(const std::string& method, const std::string& uri):
|
||||
_method(method),
|
||||
_uri(uri)
|
||||
@ -74,11 +74,31 @@ HTTPRequest::HTTPRequest(const std::string& method, const std::string& uri, cons
|
||||
}
|
||||
|
||||
|
||||
HTTPRequest::HTTPRequest(const HTTPRequest& other):
|
||||
HTTPMessage(other),
|
||||
_method(other._method),
|
||||
_uri(other._uri)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
HTTPRequest::~HTTPRequest()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
HTTPRequest& HTTPRequest::operator = (const HTTPRequest& other)
|
||||
{
|
||||
if (this != &other)
|
||||
{
|
||||
HTTPMessage::operator = (other);
|
||||
_method = other._method;
|
||||
_uri = other._uri;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
void HTTPRequest::setMethod(const std::string& method)
|
||||
{
|
||||
_method = method;
|
||||
@ -96,7 +116,7 @@ void HTTPRequest::setHost(const std::string& host)
|
||||
set(HOST, host);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void HTTPRequest::setHost(const std::string& host, Poco::UInt16 port)
|
||||
{
|
||||
std::string value;
|
||||
@ -110,7 +130,7 @@ void HTTPRequest::setHost(const std::string& host, Poco::UInt16 port)
|
||||
else
|
||||
{
|
||||
value.append(host);
|
||||
}
|
||||
}
|
||||
|
||||
if (port != 80 && port != 443)
|
||||
{
|
||||
@ -120,7 +140,7 @@ void HTTPRequest::setHost(const std::string& host, Poco::UInt16 port)
|
||||
setHost(value);
|
||||
}
|
||||
|
||||
|
||||
|
||||
const std::string& HTTPRequest::getHost() const
|
||||
{
|
||||
return get(HOST);
|
||||
@ -142,7 +162,7 @@ void HTTPRequest::setCookies(const NameValueCollection& cookies)
|
||||
add(COOKIE, cookie);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void HTTPRequest::getCookies(NameValueCollection& cookies) const
|
||||
{
|
||||
NameValueCollection::ConstIterator it = find(COOKIE);
|
||||
@ -159,37 +179,49 @@ bool HTTPRequest::hasCredentials() const
|
||||
return has(AUTHORIZATION);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void HTTPRequest::getCredentials(std::string& scheme, std::string& authInfo) const
|
||||
{
|
||||
getCredentials(AUTHORIZATION, scheme, authInfo);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void HTTPRequest::setCredentials(const std::string& scheme, const std::string& authInfo)
|
||||
{
|
||||
setCredentials(AUTHORIZATION, scheme, authInfo);
|
||||
}
|
||||
|
||||
|
||||
void HTTPRequest::removeCredentials()
|
||||
{
|
||||
erase(AUTHORIZATION);
|
||||
}
|
||||
|
||||
|
||||
bool HTTPRequest::hasProxyCredentials() const
|
||||
{
|
||||
return has(PROXY_AUTHORIZATION);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void HTTPRequest::getProxyCredentials(std::string& scheme, std::string& authInfo) const
|
||||
{
|
||||
getCredentials(PROXY_AUTHORIZATION, scheme, authInfo);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void HTTPRequest::setProxyCredentials(const std::string& scheme, const std::string& authInfo)
|
||||
{
|
||||
setCredentials(PROXY_AUTHORIZATION, scheme, authInfo);
|
||||
}
|
||||
|
||||
|
||||
void HTTPRequest::removeProxyCredentials()
|
||||
{
|
||||
erase(PROXY_AUTHORIZATION);
|
||||
}
|
||||
|
||||
|
||||
void HTTPRequest::write(std::ostream& ostr) const
|
||||
{
|
||||
ostr << _method << " " << _uri << " " << getVersion() << "\r\n";
|
||||
@ -248,7 +280,7 @@ void HTTPRequest::getCredentials(const std::string& header, std::string& scheme,
|
||||
else throw NotAuthenticatedException();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void HTTPRequest::setCredentials(const std::string& header, const std::string& scheme, const std::string& authInfo)
|
||||
{
|
||||
std::string auth(scheme);
|
||||
|
@ -108,7 +108,7 @@ HTTPResponse::HTTPResponse():
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
HTTPResponse::HTTPResponse(HTTPStatus status, const std::string& reason):
|
||||
_status(status),
|
||||
_reason(reason)
|
||||
@ -116,7 +116,7 @@ HTTPResponse::HTTPResponse(HTTPStatus status, const std::string& reason):
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
HTTPResponse::HTTPResponse(const std::string& version, HTTPStatus status, const std::string& reason):
|
||||
HTTPMessage(version),
|
||||
_status(status),
|
||||
@ -124,7 +124,7 @@ HTTPResponse::HTTPResponse(const std::string& version, HTTPStatus status, const
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
HTTPResponse::HTTPResponse(HTTPStatus status):
|
||||
_status(status),
|
||||
_reason(getReasonForStatus(status))
|
||||
@ -140,11 +140,31 @@ HTTPResponse::HTTPResponse(const std::string& version, HTTPStatus status):
|
||||
}
|
||||
|
||||
|
||||
HTTPResponse::HTTPResponse(const HTTPResponse& other):
|
||||
HTTPMessage(other),
|
||||
_status(other._status),
|
||||
_reason(other._reason)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
HTTPResponse::~HTTPResponse()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
HTTPResponse& HTTPResponse::operator = (const HTTPResponse& other)
|
||||
{
|
||||
if (this != &other)
|
||||
{
|
||||
HTTPMessage::operator = (other);
|
||||
_status = other._status;
|
||||
_reason = other._reason;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
void HTTPResponse::setStatus(HTTPStatus status)
|
||||
{
|
||||
_status = status;
|
||||
@ -155,8 +175,8 @@ void HTTPResponse::setStatus(const std::string& status)
|
||||
{
|
||||
setStatus((HTTPStatus) NumberParser::parse(status));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void HTTPResponse::setReason(const std::string& reason)
|
||||
{
|
||||
_reason = reason;
|
||||
@ -169,7 +189,7 @@ void HTTPResponse::setStatusAndReason(HTTPStatus status, const std::string& reas
|
||||
_reason = reason;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void HTTPResponse::setStatusAndReason(HTTPStatus status)
|
||||
{
|
||||
setStatusAndReason(status, getReasonForStatus(status));
|
||||
@ -181,7 +201,7 @@ void HTTPResponse::setDate(const Poco::Timestamp& dateTime)
|
||||
set(DATE, DateTimeFormatter::format(dateTime, DateTimeFormat::HTTP_FORMAT));
|
||||
}
|
||||
|
||||
|
||||
|
||||
Poco::Timestamp HTTPResponse::getDate() const
|
||||
{
|
||||
const std::string& dateTime = get(DATE);
|
||||
@ -225,7 +245,7 @@ void HTTPResponse::read(std::istream& istr)
|
||||
std::string version;
|
||||
std::string status;
|
||||
std::string reason;
|
||||
|
||||
|
||||
int ch = istr.get();
|
||||
if (istr.bad()) throw NetException("Error reading HTTP response header");
|
||||
if (ch == eof) throw NoMessageException();
|
||||
@ -255,25 +275,25 @@ const std::string& HTTPResponse::getReasonForStatus(HTTPStatus status)
|
||||
{
|
||||
switch (status)
|
||||
{
|
||||
case HTTP_CONTINUE:
|
||||
case HTTP_CONTINUE:
|
||||
return HTTP_REASON_CONTINUE;
|
||||
case HTTP_SWITCHING_PROTOCOLS:
|
||||
case HTTP_SWITCHING_PROTOCOLS:
|
||||
return HTTP_REASON_SWITCHING_PROTOCOLS;
|
||||
case HTTP_PROCESSING:
|
||||
return HTTP_REASON_PROCESSING;
|
||||
case HTTP_OK:
|
||||
case HTTP_OK:
|
||||
return HTTP_REASON_OK;
|
||||
case HTTP_CREATED:
|
||||
case HTTP_CREATED:
|
||||
return HTTP_REASON_CREATED;
|
||||
case HTTP_ACCEPTED:
|
||||
case HTTP_ACCEPTED:
|
||||
return HTTP_REASON_ACCEPTED;
|
||||
case HTTP_NONAUTHORITATIVE:
|
||||
case HTTP_NONAUTHORITATIVE:
|
||||
return HTTP_REASON_NONAUTHORITATIVE;
|
||||
case HTTP_NO_CONTENT:
|
||||
case HTTP_NO_CONTENT:
|
||||
return HTTP_REASON_NO_CONTENT;
|
||||
case HTTP_RESET_CONTENT:
|
||||
case HTTP_RESET_CONTENT:
|
||||
return HTTP_REASON_RESET_CONTENT;
|
||||
case HTTP_PARTIAL_CONTENT:
|
||||
case HTTP_PARTIAL_CONTENT:
|
||||
return HTTP_REASON_PARTIAL_CONTENT;
|
||||
case HTTP_MULTI_STATUS:
|
||||
return HTTP_REASON_MULTI_STATUS;
|
||||
@ -281,58 +301,58 @@ const std::string& HTTPResponse::getReasonForStatus(HTTPStatus status)
|
||||
return HTTP_REASON_ALREADY_REPORTED;
|
||||
case HTTP_IM_USED:
|
||||
return HTTP_REASON_IM_USED;
|
||||
case HTTP_MULTIPLE_CHOICES:
|
||||
case HTTP_MULTIPLE_CHOICES:
|
||||
return HTTP_REASON_MULTIPLE_CHOICES;
|
||||
case HTTP_MOVED_PERMANENTLY:
|
||||
case HTTP_MOVED_PERMANENTLY:
|
||||
return HTTP_REASON_MOVED_PERMANENTLY;
|
||||
case HTTP_FOUND:
|
||||
case HTTP_FOUND:
|
||||
return HTTP_REASON_FOUND;
|
||||
case HTTP_SEE_OTHER:
|
||||
case HTTP_SEE_OTHER:
|
||||
return HTTP_REASON_SEE_OTHER;
|
||||
case HTTP_NOT_MODIFIED:
|
||||
case HTTP_NOT_MODIFIED:
|
||||
return HTTP_REASON_NOT_MODIFIED;
|
||||
case HTTP_USE_PROXY:
|
||||
case HTTP_USE_PROXY:
|
||||
return HTTP_REASON_USE_PROXY;
|
||||
case HTTP_TEMPORARY_REDIRECT:
|
||||
case HTTP_TEMPORARY_REDIRECT:
|
||||
return HTTP_REASON_TEMPORARY_REDIRECT;
|
||||
case HTTP_BAD_REQUEST:
|
||||
case HTTP_BAD_REQUEST:
|
||||
return HTTP_REASON_BAD_REQUEST;
|
||||
case HTTP_UNAUTHORIZED:
|
||||
case HTTP_UNAUTHORIZED:
|
||||
return HTTP_REASON_UNAUTHORIZED;
|
||||
case HTTP_PAYMENT_REQUIRED:
|
||||
case HTTP_PAYMENT_REQUIRED:
|
||||
return HTTP_REASON_PAYMENT_REQUIRED;
|
||||
case HTTP_FORBIDDEN:
|
||||
case HTTP_FORBIDDEN:
|
||||
return HTTP_REASON_FORBIDDEN;
|
||||
case HTTP_NOT_FOUND:
|
||||
case HTTP_NOT_FOUND:
|
||||
return HTTP_REASON_NOT_FOUND;
|
||||
case HTTP_METHOD_NOT_ALLOWED:
|
||||
return HTTP_REASON_METHOD_NOT_ALLOWED;
|
||||
case HTTP_NOT_ACCEPTABLE:
|
||||
case HTTP_NOT_ACCEPTABLE:
|
||||
return HTTP_REASON_NOT_ACCEPTABLE;
|
||||
case HTTP_PROXY_AUTHENTICATION_REQUIRED:
|
||||
case HTTP_PROXY_AUTHENTICATION_REQUIRED:
|
||||
return HTTP_REASON_PROXY_AUTHENTICATION_REQUIRED;
|
||||
case HTTP_REQUEST_TIMEOUT:
|
||||
case HTTP_REQUEST_TIMEOUT:
|
||||
return HTTP_REASON_REQUEST_TIMEOUT;
|
||||
case HTTP_CONFLICT:
|
||||
case HTTP_CONFLICT:
|
||||
return HTTP_REASON_CONFLICT;
|
||||
case HTTP_GONE:
|
||||
case HTTP_GONE:
|
||||
return HTTP_REASON_GONE;
|
||||
case HTTP_LENGTH_REQUIRED:
|
||||
case HTTP_LENGTH_REQUIRED:
|
||||
return HTTP_REASON_LENGTH_REQUIRED;
|
||||
case HTTP_PRECONDITION_FAILED:
|
||||
case HTTP_PRECONDITION_FAILED:
|
||||
return HTTP_REASON_PRECONDITION_FAILED;
|
||||
case HTTP_REQUEST_ENTITY_TOO_LARGE:
|
||||
case HTTP_REQUEST_ENTITY_TOO_LARGE:
|
||||
return HTTP_REASON_REQUEST_ENTITY_TOO_LARGE;
|
||||
case HTTP_REQUEST_URI_TOO_LONG:
|
||||
case HTTP_REQUEST_URI_TOO_LONG:
|
||||
return HTTP_REASON_REQUEST_URI_TOO_LONG;
|
||||
case HTTP_UNSUPPORTED_MEDIA_TYPE:
|
||||
case HTTP_UNSUPPORTED_MEDIA_TYPE:
|
||||
return HTTP_REASON_UNSUPPORTED_MEDIA_TYPE;
|
||||
case HTTP_REQUESTED_RANGE_NOT_SATISFIABLE:
|
||||
case HTTP_REQUESTED_RANGE_NOT_SATISFIABLE:
|
||||
return HTTP_REASON_REQUESTED_RANGE_NOT_SATISFIABLE;
|
||||
case HTTP_EXPECTATION_FAILED:
|
||||
case HTTP_EXPECTATION_FAILED:
|
||||
return HTTP_REASON_EXPECTATION_FAILED;
|
||||
case HTTP_IM_A_TEAPOT:
|
||||
return HTTP_REASON_IM_A_TEAPOT;
|
||||
return HTTP_REASON_IM_A_TEAPOT;
|
||||
case HTTP_ENCHANCE_YOUR_CALM:
|
||||
return HTTP_REASON_ENCHANCE_YOUR_CALM;
|
||||
case HTTP_MISDIRECTED_REQUEST:
|
||||
@ -353,17 +373,17 @@ const std::string& HTTPResponse::getReasonForStatus(HTTPStatus status)
|
||||
return HTTP_REASON_REQUEST_HEADER_FIELDS_TOO_LARGE;
|
||||
case HTTP_UNAVAILABLE_FOR_LEGAL_REASONS:
|
||||
return HTTP_REASON_UNAVAILABLE_FOR_LEGAL_REASONS;
|
||||
case HTTP_INTERNAL_SERVER_ERROR:
|
||||
case HTTP_INTERNAL_SERVER_ERROR:
|
||||
return HTTP_REASON_INTERNAL_SERVER_ERROR;
|
||||
case HTTP_NOT_IMPLEMENTED:
|
||||
case HTTP_NOT_IMPLEMENTED:
|
||||
return HTTP_REASON_NOT_IMPLEMENTED;
|
||||
case HTTP_BAD_GATEWAY:
|
||||
case HTTP_BAD_GATEWAY:
|
||||
return HTTP_REASON_BAD_GATEWAY;
|
||||
case HTTP_SERVICE_UNAVAILABLE:
|
||||
return HTTP_REASON_SERVICE_UNAVAILABLE;
|
||||
case HTTP_GATEWAY_TIMEOUT:
|
||||
case HTTP_GATEWAY_TIMEOUT:
|
||||
return HTTP_REASON_GATEWAY_TIMEOUT;
|
||||
case HTTP_VERSION_NOT_SUPPORTED:
|
||||
case HTTP_VERSION_NOT_SUPPORTED:
|
||||
return HTTP_REASON_VERSION_NOT_SUPPORTED;
|
||||
case HTTP_VARIANT_ALSO_NEGOTIATES:
|
||||
return HTTP_REASON_VARIANT_ALSO_NEGOTIATES;
|
||||
@ -375,7 +395,7 @@ const std::string& HTTPResponse::getReasonForStatus(HTTPStatus status)
|
||||
return HTTP_REASON_NOT_EXTENDED;
|
||||
case HTTP_NETWORK_AUTHENTICATION_REQUIRED:
|
||||
return HTTP_REASON_NETWORK_AUTHENTICATION_REQUIRED;
|
||||
default:
|
||||
default:
|
||||
return HTTP_REASON_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
329
Net/src/NTLMCredentials.cpp
Normal file
329
Net/src/NTLMCredentials.cpp
Normal file
@ -0,0 +1,329 @@
|
||||
//
|
||||
// NTLMCredentials.cpp
|
||||
//
|
||||
// Library: Net
|
||||
// Package: HTTP
|
||||
// Module: NTLMCredentials
|
||||
//
|
||||
// Copyright (c) 2019, Applied Informatics Software Engineering GmbH.
|
||||
// and Contributors.
|
||||
//
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
//
|
||||
|
||||
|
||||
#include "Poco/Net/NTLMCredentials.h"
|
||||
#include "Poco/HMACEngine.h"
|
||||
#include "Poco/MD4Engine.h"
|
||||
#include "Poco/MD5Engine.h"
|
||||
#include "Poco/DigestStream.h"
|
||||
#include "Poco/StreamCopier.h"
|
||||
#include "Poco/UTF8Encoding.h"
|
||||
#include "Poco/UTF16Encoding.h"
|
||||
#include "Poco/TextConverter.h"
|
||||
#include "Poco/UTF8String.h"
|
||||
#include "Poco/Random.h"
|
||||
#include "Poco/Timestamp.h"
|
||||
#include "Poco/MemoryStream.h"
|
||||
#include <cstring>
|
||||
|
||||
|
||||
namespace Poco {
|
||||
namespace Net {
|
||||
|
||||
|
||||
const std::string NTLMCredentials::NTLMSSP("NTLMSSP");
|
||||
|
||||
|
||||
std::vector<unsigned char> NTLMCredentials::createNonce()
|
||||
{
|
||||
Poco::MD5Engine md5;
|
||||
Poco::Random rnd;
|
||||
rnd.seed();
|
||||
|
||||
Poco::UInt32 n = rnd.next();
|
||||
md5.update(&n, sizeof(n));
|
||||
|
||||
Poco::Timestamp ts;
|
||||
md5.update(&ts, sizeof(ts));
|
||||
|
||||
Poco::DigestEngine::Digest d = md5.digest();
|
||||
d.resize(8);
|
||||
|
||||
return d;
|
||||
}
|
||||
|
||||
|
||||
Poco::UInt64 NTLMCredentials::createTimestamp()
|
||||
{
|
||||
const Poco::UInt64 EPOCH_DELTA_SECONDS = 11644473600; // seconds between January 1, 1970 and January 1, 1601
|
||||
|
||||
Poco::Timestamp now;
|
||||
Poco::UInt64 ts = now.epochMicroseconds();
|
||||
ts += EPOCH_DELTA_SECONDS*1000000; // since January 1, 1601
|
||||
ts *= 10; // tenths of a microsecond
|
||||
return ts;
|
||||
}
|
||||
|
||||
|
||||
std::vector<unsigned char> NTLMCredentials::createPasswordHash(const std::string& password)
|
||||
{
|
||||
Poco::UTF8Encoding utf8;
|
||||
Poco::UTF16Encoding utf16(Poco::UTF16Encoding::LITTLE_ENDIAN_BYTE_ORDER);
|
||||
Poco::TextConverter converter(utf8, utf16);
|
||||
|
||||
std::string utf16Password;
|
||||
converter.convert(password, utf16Password);
|
||||
|
||||
Poco::MD4Engine md4;
|
||||
md4.update(utf16Password);
|
||||
return md4.digest();
|
||||
}
|
||||
|
||||
|
||||
std::vector<unsigned char> NTLMCredentials::createNTLMv2Hash(const std::string& username, const std::string& target, const std::string& password)
|
||||
{
|
||||
Poco::UTF8Encoding utf8;
|
||||
Poco::UTF16Encoding utf16(Poco::UTF16Encoding::LITTLE_ENDIAN_BYTE_ORDER);
|
||||
Poco::TextConverter converter(utf8, utf16);
|
||||
|
||||
std::vector<unsigned char> passwordHash = createPasswordHash(password);
|
||||
|
||||
std::string userDomain = Poco::UTF8::toUpper(username);
|
||||
userDomain += target;
|
||||
|
||||
std::string utf16UserDomain;
|
||||
converter.convert(userDomain, utf16UserDomain);
|
||||
|
||||
std::string passwordHashString(reinterpret_cast<const char*>(&passwordHash[0]), passwordHash.size());
|
||||
Poco::HMACEngine<Poco::MD5Engine> hmac(passwordHashString);
|
||||
hmac.update(utf16UserDomain);
|
||||
return hmac.digest();
|
||||
}
|
||||
|
||||
|
||||
std::vector<unsigned char> NTLMCredentials::createLMv2Response(const std::vector<unsigned char>& ntlm2Hash, const std::vector<unsigned char>& challenge, const std::vector<unsigned char>& nonce)
|
||||
{
|
||||
poco_assert (challenge.size() == 8);
|
||||
poco_assert (nonce.size() == 8);
|
||||
|
||||
std::vector<unsigned char> lm2Response;
|
||||
|
||||
std::string ntlm2HashString(reinterpret_cast<const char*>(&ntlm2Hash[0]), ntlm2Hash.size());
|
||||
Poco::HMACEngine<Poco::MD5Engine> hmac2(ntlm2HashString);
|
||||
hmac2.update(&challenge[0], challenge.size());
|
||||
hmac2.update(&nonce[0], nonce.size());
|
||||
lm2Response = hmac2.digest();
|
||||
lm2Response.insert(lm2Response.end(), nonce.begin(), nonce.end());
|
||||
|
||||
return lm2Response;
|
||||
}
|
||||
|
||||
|
||||
std::vector<unsigned char> NTLMCredentials::createNTLMv2Response(const std::vector<unsigned char>& ntlm2Hash, const std::vector<unsigned char>& challenge, const std::vector<unsigned char>& nonce, const std::vector<unsigned char>& targetInfo, Poco::UInt64 timestamp)
|
||||
{
|
||||
poco_assert (challenge.size() == 8);
|
||||
poco_assert (nonce.size() == 8);
|
||||
|
||||
std::vector<unsigned char> blob;
|
||||
blob.resize(28 + targetInfo.size() + 4 + 16);
|
||||
|
||||
Poco::MemoryOutputStream blobStream(reinterpret_cast<char*>(&blob[16]), blob.size() - 16);
|
||||
Poco::BinaryWriter writer(blobStream, Poco::BinaryWriter::LITTLE_ENDIAN_BYTE_ORDER);
|
||||
writer << Poco::UInt32(0x0101);
|
||||
writer << Poco::UInt32(0);
|
||||
writer << timestamp;
|
||||
writer.writeRaw(reinterpret_cast<const char*>(&nonce[0]), nonce.size());
|
||||
writer << Poco::UInt32(0);
|
||||
writer.writeRaw(reinterpret_cast<const char*>(&targetInfo[0]), targetInfo.size());
|
||||
writer << Poco::UInt32(0);
|
||||
|
||||
poco_assert_dbg (blobStream.charsWritten() == blob.size() - 16);
|
||||
|
||||
std::string ntlm2HashString(reinterpret_cast<const char*>(&ntlm2Hash[0]), ntlm2Hash.size());
|
||||
Poco::HMACEngine<Poco::MD5Engine> hmac2(ntlm2HashString);
|
||||
hmac2.update(&challenge[0], challenge.size());
|
||||
hmac2.update(&blob[16], blob.size() - 16);
|
||||
Poco::DigestEngine::Digest d = hmac2.digest();
|
||||
|
||||
poco_assert_dbg (d.size() == 16);
|
||||
|
||||
std::memcpy(&blob[0], &d[0], 16);
|
||||
|
||||
return blob;
|
||||
}
|
||||
|
||||
|
||||
std::vector<unsigned char> NTLMCredentials::formatNegotiateMessage(const NegotiateMessage& message)
|
||||
{
|
||||
Poco::UTF8Encoding utf8;
|
||||
Poco::UTF16Encoding utf16(Poco::UTF16Encoding::LITTLE_ENDIAN_BYTE_ORDER);
|
||||
Poco::TextConverter converter(utf8, utf16);
|
||||
|
||||
std::string utf16Domain;
|
||||
converter.convert(message.domain, utf16Domain);
|
||||
|
||||
std::string utf16Workstation;
|
||||
converter.convert(message.workstation, utf16Workstation);
|
||||
|
||||
std::size_t size = 8 // signature
|
||||
+ 4 // type
|
||||
+ 4 // flags
|
||||
+ 8 + utf16Domain.size()
|
||||
+ 8 + utf16Workstation.size();
|
||||
|
||||
Poco::UInt32 flags = message.flags | NTLM_FLAG_NEGOTIATE_UNICODE | NTLM_FLAG_REQUEST_TARGET | NTLM_FLAG_NEGOTIATE_NTLM | NTLM_FLAG_NEGOTIATE_NTLM2_KEY | NTLM_FLAG_NEGOTIATE_ALWAYS_SIGN;
|
||||
if (!utf16Domain.empty()) flags |= NTLM_FLAG_DOMAIN_SUPPLIED;
|
||||
if (!utf16Workstation.empty()) flags |= NTLM_FLAG_WORKST_SUPPLIED;
|
||||
|
||||
BufferDesc domainDesc(utf16Domain.size(), 8 + 4 + 4 + 8);
|
||||
BufferDesc workstDesc(utf16Workstation.size(), domainDesc.offset + domainDesc.length);
|
||||
|
||||
std::vector<unsigned char> buffer(size);
|
||||
Poco::MemoryOutputStream bufferStream(reinterpret_cast<char*>(&buffer[0]), buffer.size());
|
||||
Poco::BinaryWriter writer(bufferStream, Poco::BinaryWriter::LITTLE_ENDIAN_BYTE_ORDER);
|
||||
writer.writeRaw(NTLMSSP.c_str(), 8);
|
||||
writer << Poco::UInt32(NTLM_MESSAGE_TYPE_NEGOTIATE);
|
||||
writer << flags;
|
||||
writeBufferDesc(writer, domainDesc);
|
||||
writeBufferDesc(writer, workstDesc);
|
||||
writer.writeRaw(utf16Domain);
|
||||
writer.writeRaw(utf16Workstation);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
|
||||
bool NTLMCredentials::parseChallengeMessage(const unsigned char* buffer, std::size_t size, ChallengeMessage& message)
|
||||
{
|
||||
Poco::MemoryInputStream istr(reinterpret_cast<const char*>(buffer), size);
|
||||
Poco::BinaryReader reader(istr, Poco::BinaryReader::LITTLE_ENDIAN_BYTE_ORDER);
|
||||
|
||||
std::string signature;
|
||||
reader.readRaw(7, signature);
|
||||
if (signature != NTLMSSP) return false;
|
||||
|
||||
Poco::UInt8 zero;
|
||||
reader >> zero;
|
||||
if (zero != 0) return false;
|
||||
|
||||
Poco::UInt32 type;
|
||||
reader >> type;
|
||||
if (type != NTLM_MESSAGE_TYPE_CHALLENGE) return false;
|
||||
|
||||
BufferDesc targetDesc;
|
||||
readBufferDesc(reader, targetDesc);
|
||||
if (targetDesc.offset + targetDesc.length > size) return false;
|
||||
|
||||
reader >> message.flags;
|
||||
|
||||
message.challenge.resize(8);
|
||||
reader.readRaw(reinterpret_cast<char*>(&message.challenge[0]), 8);
|
||||
|
||||
if (message.flags & NTLM_FLAG_NEGOTIATE_TARGET)
|
||||
{
|
||||
Poco::UInt64 reserved;
|
||||
reader >> reserved;
|
||||
}
|
||||
|
||||
BufferDesc targetInfoDesc;
|
||||
if (message.flags & NTLM_FLAG_NEGOTIATE_TARGET)
|
||||
{
|
||||
readBufferDesc(reader, targetInfoDesc);
|
||||
if (targetInfoDesc.offset + targetInfoDesc.length > size) return false;
|
||||
}
|
||||
|
||||
if (targetDesc.length > 0)
|
||||
{
|
||||
if (message.flags & NTLM_FLAG_NEGOTIATE_UNICODE)
|
||||
{
|
||||
Poco::UTF16Encoding utf16(Poco::UTF16Encoding::LITTLE_ENDIAN_BYTE_ORDER);
|
||||
Poco::UTF8Encoding utf8;
|
||||
Poco::TextConverter converter(utf16, utf8);
|
||||
converter.convert(buffer + targetDesc.offset, targetDesc.length, message.target);
|
||||
if (targetDesc.reserved == 0) message.target.resize(std::strlen(message.target.c_str()));
|
||||
}
|
||||
else
|
||||
{
|
||||
message.target.assign(buffer + targetDesc.offset, buffer + targetDesc.offset + targetDesc.length);
|
||||
}
|
||||
}
|
||||
|
||||
if (targetInfoDesc.length > 0)
|
||||
{
|
||||
message.targetInfo.assign(buffer + targetInfoDesc.offset, buffer + targetInfoDesc.offset + targetInfoDesc.length);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
std::vector<unsigned char> NTLMCredentials::formatAuthenticateMessage(const AuthenticateMessage& message)
|
||||
{
|
||||
Poco::UTF8Encoding utf8;
|
||||
Poco::UTF16Encoding utf16(Poco::UTF16Encoding::LITTLE_ENDIAN_BYTE_ORDER);
|
||||
Poco::TextConverter converter(utf8, utf16);
|
||||
|
||||
std::string utf16Target;
|
||||
converter.convert(message.target, utf16Target);
|
||||
|
||||
std::string utf16Username;
|
||||
converter.convert(message.username, utf16Username);
|
||||
|
||||
std::string utf16Workstation;
|
||||
converter.convert(message.workstation, utf16Workstation);
|
||||
|
||||
std::size_t size = 8 // signature
|
||||
+ 4 // type
|
||||
+ 8 + message.lmResponse.size()
|
||||
+ 8 + message.ntlmResponse.size()
|
||||
+ 8 + utf16Target.size()
|
||||
+ 8 + utf16Username.size()
|
||||
+ 8 + utf16Workstation.size()
|
||||
+ 8 // session key
|
||||
+ 4; // flags
|
||||
|
||||
Poco::UInt32 flags = message.flags | NTLM_FLAG_NEGOTIATE_UNICODE;
|
||||
|
||||
BufferDesc lmDesc(message.lmResponse.size(), 64);
|
||||
BufferDesc ntlmDesc(message.ntlmResponse.size(), lmDesc.offset + lmDesc.length);
|
||||
BufferDesc targetDesc(utf16Target.size(), ntlmDesc.offset + ntlmDesc.length);
|
||||
BufferDesc usernameDesc(utf16Username.size(), targetDesc.offset + targetDesc.length);
|
||||
BufferDesc workstDesc(utf16Workstation.size(), usernameDesc.offset + usernameDesc.length);
|
||||
BufferDesc sessionKeyDesc(0, workstDesc.offset + workstDesc.length);
|
||||
|
||||
std::vector<unsigned char> buffer(size);
|
||||
Poco::MemoryOutputStream bufferStream(reinterpret_cast<char*>(&buffer[0]), buffer.size());
|
||||
Poco::BinaryWriter writer(bufferStream, Poco::BinaryWriter::LITTLE_ENDIAN_BYTE_ORDER);
|
||||
writer.writeRaw(NTLMSSP.c_str(), 8);
|
||||
writer << Poco::UInt32(NTLM_MESSAGE_TYPE_AUTHENTICATE);
|
||||
writeBufferDesc(writer, lmDesc);
|
||||
writeBufferDesc(writer, ntlmDesc);
|
||||
writeBufferDesc(writer, targetDesc);
|
||||
writeBufferDesc(writer, usernameDesc);
|
||||
writeBufferDesc(writer, workstDesc);
|
||||
writeBufferDesc(writer, sessionKeyDesc);
|
||||
writer << flags;
|
||||
writer.writeRaw(reinterpret_cast<const char*>(&message.lmResponse[0]), message.lmResponse.size());
|
||||
writer.writeRaw(reinterpret_cast<const char*>(&message.ntlmResponse[0]), message.ntlmResponse.size());
|
||||
writer.writeRaw(utf16Target);
|
||||
writer.writeRaw(utf16Username);
|
||||
writer.writeRaw(utf16Workstation);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
|
||||
void NTLMCredentials::readBufferDesc(Poco::BinaryReader& reader, BufferDesc& desc)
|
||||
{
|
||||
reader >> desc.length >> desc.reserved >> desc.offset;
|
||||
}
|
||||
|
||||
|
||||
void NTLMCredentials::writeBufferDesc(Poco::BinaryWriter& writer, const BufferDesc& desc)
|
||||
{
|
||||
writer << desc.length << desc.reserved << desc.offset;
|
||||
}
|
||||
|
||||
|
||||
} } // namespace Poco::Net
|
@ -27,7 +27,8 @@ objects = \
|
||||
WebSocketTest WebSocketTestSuite \
|
||||
SyslogTest \
|
||||
OAuth10CredentialsTest OAuth20CredentialsTest OAuthTestSuite \
|
||||
PollSetTest UDPServerTest UDPServerTestSuite
|
||||
PollSetTest UDPServerTest UDPServerTestSuite \
|
||||
NTLMCredentialsTest
|
||||
|
||||
target = testrunner
|
||||
target_version = 1
|
||||
|
@ -44,7 +44,7 @@ void HTTPCredentialsTest::testBasicCredentials()
|
||||
{
|
||||
HTTPRequest request;
|
||||
assertTrue (!request.hasCredentials());
|
||||
|
||||
|
||||
HTTPBasicCredentials cred("user", "secret");
|
||||
cred.authenticate(request);
|
||||
assertTrue (request.hasCredentials());
|
||||
@ -53,7 +53,7 @@ void HTTPCredentialsTest::testBasicCredentials()
|
||||
request.getCredentials(scheme, info);
|
||||
assertTrue (scheme == "Basic");
|
||||
assertTrue (info == "dXNlcjpzZWNyZXQ=");
|
||||
|
||||
|
||||
HTTPBasicCredentials cred2(request);
|
||||
assertTrue (cred2.getUsername() == "user");
|
||||
assertTrue (cred2.getPassword() == "secret");
|
||||
@ -64,7 +64,7 @@ void HTTPCredentialsTest::testProxyBasicCredentials()
|
||||
{
|
||||
HTTPRequest request;
|
||||
assertTrue (!request.hasProxyCredentials());
|
||||
|
||||
|
||||
HTTPBasicCredentials cred("user", "secret");
|
||||
cred.proxyAuthenticate(request);
|
||||
assertTrue (request.hasProxyCredentials());
|
||||
@ -79,7 +79,7 @@ void HTTPCredentialsTest::testProxyBasicCredentials()
|
||||
void HTTPCredentialsTest::testBadCredentials()
|
||||
{
|
||||
HTTPRequest request;
|
||||
|
||||
|
||||
std::string scheme;
|
||||
std::string info;
|
||||
try
|
||||
@ -90,12 +90,12 @@ void HTTPCredentialsTest::testBadCredentials()
|
||||
catch (NotAuthenticatedException&)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
request.setCredentials("Test", "SomeData");
|
||||
request.getCredentials(scheme, info);
|
||||
assertTrue (scheme == "Test");
|
||||
assertTrue (info == "SomeData");
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
HTTPBasicCredentials cred(request);
|
||||
@ -111,7 +111,7 @@ void HTTPCredentialsTest::testAuthenticationParams()
|
||||
{
|
||||
const std::string authInfo("nonce=\"212573bb90170538efad012978ab811f%lu\", realm=\"TestDigest\", response=\"40e4889cfbd0e561f71e3107a2863bc4\", uri=\"/digest/\", username=\"user\"");
|
||||
HTTPAuthenticationParams params(authInfo);
|
||||
|
||||
|
||||
assertTrue (params["nonce"] == "212573bb90170538efad012978ab811f%lu");
|
||||
assertTrue (params["realm"] == "TestDigest");
|
||||
assertTrue (params["response"] == "40e4889cfbd0e561f71e3107a2863bc4");
|
||||
@ -119,7 +119,7 @@ void HTTPCredentialsTest::testAuthenticationParams()
|
||||
assertTrue (params["username"] == "user");
|
||||
assertTrue (params.size() == 5);
|
||||
assertTrue (params.toString() == authInfo);
|
||||
|
||||
|
||||
params.clear();
|
||||
HTTPRequest request;
|
||||
request.set("Authorization", "Digest " + authInfo);
|
||||
@ -134,22 +134,29 @@ void HTTPCredentialsTest::testAuthenticationParams()
|
||||
|
||||
params.clear();
|
||||
HTTPResponse response;
|
||||
response.set("WWW-Authenticate", "Digest realm=\"TestDigest\", nonce=\"212573bb90170538efad012978ab811f%lu\"");
|
||||
response.set("WWW-Authenticate", "Digest realm=\"TestDigest\", nonce=\"212573bb90170538efad012978ab811f%lu\"");
|
||||
params.fromResponse(response);
|
||||
|
||||
|
||||
assertTrue (params["realm"] == "TestDigest");
|
||||
assertTrue (params["nonce"] == "212573bb90170538efad012978ab811f%lu");
|
||||
assertTrue (params.size() == 2);
|
||||
|
||||
params.clear();
|
||||
response.set("WWW-Authenticate", "NTLM TlRMTVNTUAACAAAADAAMADAAAAABAoEAASNFZ4mrze8AAAAAAAAAAGIAYgA8AAAARABPAE0AQQBJAE4AAgAMAEQATwBNAEEASQBOAAEADABTAEUAUgBWAEUAUgAEABQAZABvAG0AYQBpAG4ALgBjAG8AbQADACIAcwBlAHIAdgBlAHIALgBkAG8AbQBhAGkAbgAuAGMAbwBtAAAAAAA");
|
||||
params.fromResponse(response);
|
||||
|
||||
assertTrue (params["NTLM"] == "TlRMTVNTUAACAAAADAAMADAAAAABAoEAASNFZ4mrze8AAAAAAAAAAGIAYgA8AAAARABPAE0AQQBJAE4AAgAMAEQATwBNAEEASQBOAAEADABTAEUAUgBWAEUAUgAEABQAZABvAG0AYQBpAG4ALgBjAG8AbQADACIAcwBlAHIAdgBlAHIALgBkAG8AbQBhAGkAbgAuAGMAbwBtAAAAAAA");
|
||||
assertTrue (params.size() == 1);
|
||||
}
|
||||
|
||||
|
||||
void HTTPCredentialsTest::testAuthenticationParamsMultipleHeaders()
|
||||
{
|
||||
HTTPResponse response;
|
||||
response.add("WWW-Authenticate", "Unsupported realm=\"TestUnsupported\"");
|
||||
response.add("WWW-Authenticate", "Digest realm=\"TestDigest\", nonce=\"212573bb90170538efad012978ab811f%lu\"");
|
||||
response.add("WWW-Authenticate", "Unsupported realm=\"TestUnsupported\"");
|
||||
response.add("WWW-Authenticate", "Digest realm=\"TestDigest\", nonce=\"212573bb90170538efad012978ab811f%lu\"");
|
||||
HTTPAuthenticationParams params(response);
|
||||
|
||||
|
||||
assertTrue (params["realm"] == "TestDigest");
|
||||
assertTrue (params["nonce"] == "212573bb90170538efad012978ab811f%lu");
|
||||
assertTrue (params.size() == 2);
|
||||
@ -161,7 +168,7 @@ void HTTPCredentialsTest::testDigestCredentials()
|
||||
HTTPDigestCredentials creds("user", "s3cr3t");
|
||||
HTTPRequest request(HTTPRequest::HTTP_GET, "/digest/");
|
||||
HTTPResponse response;
|
||||
response.set("WWW-Authenticate", "Digest realm=\"TestDigest\", nonce=\"212573bb90170538efad012978ab811f%lu\"");
|
||||
response.set("WWW-Authenticate", "Digest realm=\"TestDigest\", nonce=\"212573bb90170538efad012978ab811f%lu\"");
|
||||
creds.authenticate(request, response);
|
||||
std::string auth = request.get("Authorization");
|
||||
assertTrue (auth == "Digest username=\"user\", nonce=\"212573bb90170538efad012978ab811f%lu\", realm=\"TestDigest\", uri=\"/digest/\", response=\"40e4889cfbd0e561f71e3107a2863bc4\"");
|
||||
@ -173,9 +180,9 @@ void HTTPCredentialsTest::testDigestCredentialsQoP()
|
||||
HTTPDigestCredentials creds("user", "s3cr3t");
|
||||
HTTPRequest request(HTTPRequest::HTTP_GET, "/digest/");
|
||||
HTTPResponse response;
|
||||
response.set("WWW-Authenticate", "Digest realm=\"TestDigest\", nonce=\"212573bb90170538efad012978ab811f%lu\", opaque=\"opaque\", qop=\"auth,auth-int\"");
|
||||
response.set("WWW-Authenticate", "Digest realm=\"TestDigest\", nonce=\"212573bb90170538efad012978ab811f%lu\", opaque=\"opaque\", qop=\"auth,auth-int\"");
|
||||
creds.authenticate(request, response);
|
||||
|
||||
|
||||
HTTPAuthenticationParams params(request);
|
||||
assertTrue (params["nonce"] == "212573bb90170538efad012978ab811f%lu");
|
||||
assertTrue (params["realm"] == "TestDigest");
|
||||
@ -187,12 +194,12 @@ void HTTPCredentialsTest::testDigestCredentialsQoP()
|
||||
assertTrue (params["nc"] == "00000001");
|
||||
assertTrue (params["qop"] == "auth");
|
||||
assertTrue (params.size() == 9);
|
||||
|
||||
|
||||
std::string cnonce = params["cnonce"];
|
||||
std::string aresp = params["response"];
|
||||
|
||||
|
||||
params.clear();
|
||||
|
||||
|
||||
creds.updateAuthInfo(request);
|
||||
params.fromRequest(request);
|
||||
assertTrue (params["nonce"] == "212573bb90170538efad012978ab811f%lu");
|
||||
@ -213,8 +220,8 @@ void HTTPCredentialsTest::testCredentialsBasic()
|
||||
HTTPCredentials creds("user", "s3cr3t");
|
||||
HTTPRequest request(HTTPRequest::HTTP_GET, "/basic/");
|
||||
HTTPResponse response;
|
||||
response.set("WWW-Authenticate", "Basic realm=\"TestBasic\"");
|
||||
creds.authenticate(request, response);
|
||||
response.set("WWW-Authenticate", "Basic realm=\"TestBasic\"");
|
||||
creds.authenticate(request, response);
|
||||
assertTrue (request.get("Authorization") == "Basic dXNlcjpzM2NyM3Q=");
|
||||
}
|
||||
|
||||
@ -224,8 +231,8 @@ void HTTPCredentialsTest::testProxyCredentialsBasic()
|
||||
HTTPCredentials creds("user", "s3cr3t");
|
||||
HTTPRequest request(HTTPRequest::HTTP_GET, "/basic/");
|
||||
HTTPResponse response;
|
||||
response.set("Proxy-Authenticate", "Basic realm=\"TestBasic\"");
|
||||
creds.proxyAuthenticate(request, response);
|
||||
response.set("Proxy-Authenticate", "Basic realm=\"TestBasic\"");
|
||||
creds.proxyAuthenticate(request, response);
|
||||
assertTrue (request.get("Proxy-Authorization") == "Basic dXNlcjpzM2NyM3Q=");
|
||||
}
|
||||
|
||||
@ -235,7 +242,7 @@ void HTTPCredentialsTest::testCredentialsDigest()
|
||||
HTTPCredentials creds("user", "s3cr3t");
|
||||
HTTPRequest request(HTTPRequest::HTTP_GET, "/digest/");
|
||||
HTTPResponse response;
|
||||
response.set("WWW-Authenticate", "Digest realm=\"TestDigest\", nonce=\"212573bb90170538efad012978ab811f%lu\"");
|
||||
response.set("WWW-Authenticate", "Digest realm=\"TestDigest\", nonce=\"212573bb90170538efad012978ab811f%lu\"");
|
||||
creds.authenticate(request, response);
|
||||
std::string auth = request.get("Authorization");
|
||||
assertTrue (auth == "Digest username=\"user\", nonce=\"212573bb90170538efad012978ab811f%lu\", realm=\"TestDigest\", uri=\"/digest/\", response=\"40e4889cfbd0e561f71e3107a2863bc4\"");
|
||||
@ -247,8 +254,8 @@ void HTTPCredentialsTest::testCredentialsDigestMultipleHeaders()
|
||||
HTTPCredentials creds("user", "s3cr3t");
|
||||
HTTPRequest request(HTTPRequest::HTTP_GET, "/digest/");
|
||||
HTTPResponse response;
|
||||
response.add("WWW-Authenticate", "Unsupported realm=\"TestUnsupported\"");
|
||||
response.add("WWW-Authenticate", "Digest realm=\"TestDigest\", nonce=\"212573bb90170538efad012978ab811f%lu\"");
|
||||
response.add("WWW-Authenticate", "Unsupported realm=\"TestUnsupported\"");
|
||||
response.add("WWW-Authenticate", "Digest realm=\"TestDigest\", nonce=\"212573bb90170538efad012978ab811f%lu\"");
|
||||
creds.authenticate(request, response);
|
||||
std::string auth = request.get("Authorization");
|
||||
assertTrue (auth == "Digest username=\"user\", nonce=\"212573bb90170538efad012978ab811f%lu\", realm=\"TestDigest\", uri=\"/digest/\", response=\"40e4889cfbd0e561f71e3107a2863bc4\"");
|
||||
@ -260,8 +267,8 @@ void HTTPCredentialsTest::testProxyCredentialsDigest()
|
||||
HTTPCredentials creds("user", "s3cr3t");
|
||||
HTTPRequest request(HTTPRequest::HTTP_GET, "/digest/");
|
||||
HTTPResponse response;
|
||||
response.set("Proxy-Authenticate", "Digest realm=\"TestDigest\", nonce=\"212573bb90170538efad012978ab811f%lu\"");
|
||||
creds.proxyAuthenticate(request, response);
|
||||
response.set("Proxy-Authenticate", "Digest realm=\"TestDigest\", nonce=\"212573bb90170538efad012978ab811f%lu\"");
|
||||
creds.proxyAuthenticate(request, response);
|
||||
assertTrue (request.get("Proxy-Authorization") == "Digest username=\"user\", nonce=\"212573bb90170538efad012978ab811f%lu\", realm=\"TestDigest\", uri=\"/digest/\", response=\"40e4889cfbd0e561f71e3107a2863bc4\"");
|
||||
}
|
||||
|
||||
@ -282,10 +289,10 @@ void HTTPCredentialsTest::testVerifyAuthInfo()
|
||||
HTTPDigestCredentials creds("user", "s3cr3t");
|
||||
HTTPRequest request(HTTPRequest::HTTP_GET, "/digest/");
|
||||
HTTPResponse response;
|
||||
response.set("WWW-Authenticate", "Digest realm=\"TestDigest\", nonce=\"212573bb90170538efad012978ab811f%lu\"");
|
||||
response.set("WWW-Authenticate", "Digest realm=\"TestDigest\", nonce=\"212573bb90170538efad012978ab811f%lu\"");
|
||||
creds.authenticate(request, response);
|
||||
assertTrue (creds.verifyAuthInfo(request));
|
||||
|
||||
|
||||
request.set("Authorization", "Digest nonce=\"212573bb90170538efad012978ab811f%lu\", realm=\"TestDigest\", response=\"xxe4889cfbd0e561f71e3107a2863bc4\", uri=\"/digest/\", username=\"user\"");
|
||||
assertTrue (!creds.verifyAuthInfo(request));
|
||||
}
|
||||
@ -296,10 +303,10 @@ void HTTPCredentialsTest::testVerifyAuthInfoQoP()
|
||||
HTTPDigestCredentials creds("user", "s3cr3t");
|
||||
HTTPRequest request(HTTPRequest::HTTP_GET, "/digest/");
|
||||
HTTPResponse response;
|
||||
response.set("WWW-Authenticate", "Digest realm=\"TestDigest\", nonce=\"212573bb90170538efad012978ab811f%lu\", opaque=\"opaque\", qop=\"auth,auth-int\"");
|
||||
response.set("WWW-Authenticate", "Digest realm=\"TestDigest\", nonce=\"212573bb90170538efad012978ab811f%lu\", opaque=\"opaque\", qop=\"auth,auth-int\"");
|
||||
creds.authenticate(request, response);
|
||||
assertTrue (creds.verifyAuthInfo(request));
|
||||
|
||||
|
||||
request.set("Authorization", "Digest cnonce=\"f9c80ffd1c3bc4ee47ed92b704ba75a4\", nc=00000001, nonce=\"212573bb90170538efad012978ab811f%lu\", opaque=\"opaque\", qop=\"auth\", realm=\"TestDigest\", response=\"ff0e90b9aa019120ea0ed6e23ce95d9a\", uri=\"/digest/\", username=\"user\"");
|
||||
assertTrue (!creds.verifyAuthInfo(request));
|
||||
}
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "HTTPResponseTest.h"
|
||||
#include "HTTPCookieTest.h"
|
||||
#include "HTTPCredentialsTest.h"
|
||||
#include "NTLMCredentialsTest.h"
|
||||
|
||||
|
||||
CppUnit::Test* HTTPTestSuite::suite()
|
||||
@ -23,6 +24,7 @@ CppUnit::Test* HTTPTestSuite::suite()
|
||||
pSuite->addTest(HTTPResponseTest::suite());
|
||||
pSuite->addTest(HTTPCookieTest::suite());
|
||||
pSuite->addTest(HTTPCredentialsTest::suite());
|
||||
pSuite->addTest(NTLMCredentialsTest::suite());
|
||||
|
||||
return pSuite;
|
||||
}
|
||||
|
279
Net/testsuite/src/NTLMCredentialsTest.cpp
Normal file
279
Net/testsuite/src/NTLMCredentialsTest.cpp
Normal file
@ -0,0 +1,279 @@
|
||||
//
|
||||
// NTLMCredentialsTest.cpp
|
||||
//
|
||||
// Copyright (c) 2014, Applied Informatics Software Engineering GmbH.
|
||||
// and Contributors.
|
||||
//
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
//
|
||||
|
||||
|
||||
#include "NTLMCredentialsTest.h"
|
||||
#include "CppUnit/TestCaller.h"
|
||||
#include "CppUnit/TestSuite.h"
|
||||
#include "Poco/Net/NTLMCredentials.h"
|
||||
#include "Poco/DigestEngine.h"
|
||||
|
||||
|
||||
using Poco::Net::NTLMCredentials;
|
||||
|
||||
|
||||
NTLMCredentialsTest::NTLMCredentialsTest(const std::string& name): CppUnit::TestCase(name)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
NTLMCredentialsTest::~NTLMCredentialsTest()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void NTLMCredentialsTest::testNonce()
|
||||
{
|
||||
std::vector<unsigned char> nonce1 = NTLMCredentials::createNonce();
|
||||
assertTrue (nonce1.size() == 8);
|
||||
|
||||
std::vector<unsigned char> nonce2 = NTLMCredentials::createNonce();
|
||||
assertTrue (nonce2.size() == 8);
|
||||
|
||||
assertTrue (nonce1 != nonce2);
|
||||
}
|
||||
|
||||
|
||||
void NTLMCredentialsTest::testPasswordHash()
|
||||
{
|
||||
std::vector<unsigned char> passHash = NTLMCredentials::createPasswordHash("SecREt01");
|
||||
std::string passHashHex = Poco::DigestEngine::digestToHex(passHash);
|
||||
assertTrue (passHashHex == "cd06ca7c7e10c99b1d33b7485a2ed808");
|
||||
}
|
||||
|
||||
|
||||
void NTLMCredentialsTest::testNTLMv2Hash()
|
||||
{
|
||||
std::vector<unsigned char> ntlm2Hash = NTLMCredentials::createNTLMv2Hash("user", "DOMAIN", "SecREt01");
|
||||
std::string ntlm2HashHex = Poco::DigestEngine::digestToHex(ntlm2Hash);
|
||||
assertTrue (ntlm2HashHex == "04b8e0ba74289cc540826bab1dee63ae");
|
||||
}
|
||||
|
||||
|
||||
void NTLMCredentialsTest::testLMv2Response()
|
||||
{
|
||||
static const unsigned char CHALLENGE[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef};
|
||||
static const unsigned char NONCE[] = {0xff, 0xff, 0xff, 0x00, 0x11, 0x22, 0x33, 0x44};
|
||||
|
||||
std::vector<unsigned char> challenge(CHALLENGE, CHALLENGE + 8);
|
||||
std::vector<unsigned char> nonce(NONCE, NONCE + 8);
|
||||
|
||||
std::vector<unsigned char> ntlm2Hash = NTLMCredentials::createNTLMv2Hash("user", "DOMAIN", "SecREt01");
|
||||
std::vector<unsigned char> lm2Response = NTLMCredentials::createLMv2Response(ntlm2Hash, challenge, nonce);
|
||||
|
||||
std::string lm2ResponseHex = Poco::DigestEngine::digestToHex(lm2Response);
|
||||
assertTrue (lm2ResponseHex == "d6e6152ea25d03b7c6ba6629c2d6aaf0ffffff0011223344");
|
||||
}
|
||||
|
||||
|
||||
void NTLMCredentialsTest::testNTLMv2Response()
|
||||
{
|
||||
static const unsigned char CHALLENGE[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef};
|
||||
static const unsigned char NONCE[] = {0xff, 0xff, 0xff, 0x00, 0x11, 0x22, 0x33, 0x44};
|
||||
static const unsigned char TARGET_INFO[] = {
|
||||
0x02, 0x00, 0x0c, 0x00, 0x44, 0x00, 0x4f, 0x00,
|
||||
0x4d, 0x00, 0x41, 0x00, 0x49, 0x00, 0x4e, 0x00,
|
||||
0x01, 0x00, 0x0c, 0x00, 0x53, 0x00, 0x45, 0x00,
|
||||
0x52, 0x00, 0x56, 0x00, 0x45, 0x00, 0x52, 0x00,
|
||||
0x04, 0x00, 0x14, 0x00, 0x64, 0x00, 0x6f, 0x00,
|
||||
0x6d, 0x00, 0x61, 0x00, 0x69, 0x00, 0x6e, 0x00,
|
||||
0x2e, 0x00, 0x63, 0x00, 0x6f, 0x00, 0x6d, 0x00,
|
||||
0x03, 0x00, 0x22, 0x00, 0x73, 0x00, 0x65, 0x00,
|
||||
0x72, 0x00, 0x76, 0x00, 0x65, 0x00, 0x72, 0x00,
|
||||
0x2e, 0x00, 0x64, 0x00, 0x6f, 0x00, 0x6d, 0x00,
|
||||
0x61, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x2e, 0x00,
|
||||
0x63, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00
|
||||
};
|
||||
|
||||
std::vector<unsigned char> challenge(CHALLENGE, CHALLENGE + 8);
|
||||
std::vector<unsigned char> nonce(NONCE, NONCE + 8);
|
||||
std::vector<unsigned char> targetInfo(TARGET_INFO, TARGET_INFO + sizeof(TARGET_INFO));
|
||||
|
||||
std::vector<unsigned char> ntlm2Hash = NTLMCredentials::createNTLMv2Hash("user", "DOMAIN", "SecREt01");
|
||||
Poco::UInt64 timestamp = Poco::UInt64(12700317600)*10000000;
|
||||
|
||||
std::vector<unsigned char> ntlm2Response = NTLMCredentials::createNTLMv2Response(
|
||||
ntlm2Hash,
|
||||
challenge,
|
||||
nonce,
|
||||
targetInfo,
|
||||
timestamp);
|
||||
|
||||
std::string ntlm2ResponseHex = Poco::DigestEngine::digestToHex(ntlm2Response);
|
||||
|
||||
assertTrue (ntlm2ResponseHex ==
|
||||
"cbabbca713eb795d04c97abc01ee4983"
|
||||
"01010000000000000090d336b734c301"
|
||||
"ffffff00112233440000000002000c00"
|
||||
"44004f004d00410049004e0001000c00"
|
||||
"53004500520056004500520004001400"
|
||||
"64006f006d00610069006e002e006300"
|
||||
"6f006d00030022007300650072007600"
|
||||
"650072002e0064006f006d0061006900"
|
||||
"6e002e0063006f006d00000000000000"
|
||||
"0000"
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
void NTLMCredentialsTest::testFormatNegotiateMessage()
|
||||
{
|
||||
NTLMCredentials::NegotiateMessage msg1;
|
||||
msg1.flags = 0;
|
||||
|
||||
std::vector<unsigned char> msg1Buffer = NTLMCredentials::formatNegotiateMessage(msg1);
|
||||
std::string msg1BufferHex = Poco::DigestEngine::digestToHex(msg1Buffer);
|
||||
|
||||
assertTrue (msg1BufferHex == "4e544c4d53535000010000000582080000000000180000000000000018000000");
|
||||
|
||||
msg1.domain = "DOMAIN";
|
||||
msg1Buffer = NTLMCredentials::formatNegotiateMessage(msg1);
|
||||
msg1BufferHex = Poco::DigestEngine::digestToHex(msg1Buffer);
|
||||
|
||||
assertTrue (msg1BufferHex == "4e544c4d5353500001000000059208000c000c0018000000000000002400000044004f004d00410049004e00");
|
||||
|
||||
msg1.workstation = "WORKST";
|
||||
msg1Buffer = NTLMCredentials::formatNegotiateMessage(msg1);
|
||||
msg1BufferHex = Poco::DigestEngine::digestToHex(msg1Buffer);
|
||||
|
||||
assertTrue (msg1BufferHex == "4e544c4d535350000100000005b208000c000c00180000000c000c002400000044004f004d00410049004e0057004f0052004b0053005400");
|
||||
}
|
||||
|
||||
|
||||
void NTLMCredentialsTest::testParseChallengeMessage()
|
||||
{
|
||||
const unsigned char BUFFER[] = {
|
||||
0x4e, 0x54, 0x4c, 0x4d, 0x53, 0x53, 0x50, 0x00,
|
||||
0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00,
|
||||
0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef
|
||||
};
|
||||
|
||||
NTLMCredentials::ChallengeMessage msg2;
|
||||
bool ok = NTLMCredentials::parseChallengeMessage(BUFFER, sizeof(BUFFER), msg2);
|
||||
|
||||
assertTrue (ok);
|
||||
assertTrue (msg2.flags == (NTLMCredentials::NTLM_FLAG_NEGOTIATE_OEM | NTLMCredentials::NTLM_FLAG_NEGOTIATE_NTLM));
|
||||
assertTrue (msg2.challenge.size() == 8);
|
||||
assertTrue (msg2.targetInfo.empty());
|
||||
|
||||
assertTrue (msg2.challenge[0] == 0x01);
|
||||
assertTrue (msg2.challenge[1] == 0x23);
|
||||
assertTrue (msg2.challenge[7] == 0xef);
|
||||
}
|
||||
|
||||
|
||||
void NTLMCredentialsTest::testParseChallengeMessageWithTargetInfo()
|
||||
{
|
||||
const unsigned char BUFFER[] = {
|
||||
0x4e, 0x54, 0x4c, 0x4d, 0x53, 0x53, 0x50, 0x00,
|
||||
0x02, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x0c, 0x00,
|
||||
0x30, 0x00, 0x00, 0x00, 0x01, 0x02, 0x81, 0x00,
|
||||
0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x62, 0x00, 0x62, 0x00, 0x3c, 0x00, 0x00, 0x00,
|
||||
0x44, 0x00, 0x4f, 0x00, 0x4d, 0x00, 0x41, 0x00,
|
||||
0x49, 0x00, 0x4e, 0x00, 0x02, 0x00, 0x0c, 0x00,
|
||||
0x44, 0x00, 0x4f, 0x00, 0x4d, 0x00, 0x41, 0x00,
|
||||
0x49, 0x00, 0x4e, 0x00, 0x01, 0x00, 0x0c, 0x00,
|
||||
0x53, 0x00, 0x45, 0x00, 0x52, 0x00, 0x56, 0x00,
|
||||
0x45, 0x00, 0x52, 0x00, 0x04, 0x00, 0x14, 0x00,
|
||||
0x64, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x61, 0x00,
|
||||
0x69, 0x00, 0x6e, 0x00, 0x2e, 0x00, 0x63, 0x00,
|
||||
0x6f, 0x00, 0x6d, 0x00, 0x03, 0x00, 0x22, 0x00,
|
||||
0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x76, 0x00,
|
||||
0x65, 0x00, 0x72, 0x00, 0x2e, 0x00, 0x64, 0x00,
|
||||
0x6f, 0x00, 0x6d, 0x00, 0x61, 0x00, 0x69, 0x00,
|
||||
0x6e, 0x00, 0x2e, 0x00, 0x63, 0x00, 0x6f, 0x00,
|
||||
0x6d, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
NTLMCredentials::ChallengeMessage msg2;
|
||||
bool ok = NTLMCredentials::parseChallengeMessage(BUFFER, sizeof(BUFFER), msg2);
|
||||
|
||||
assertTrue (ok);
|
||||
assertTrue (msg2.flags == (NTLMCredentials::NTLM_FLAG_NEGOTIATE_UNICODE | NTLMCredentials::NTLM_FLAG_NEGOTIATE_NTLM | NTLMCredentials::NTLM_FLAG_NEGOTIATE_TARGET | NTLMCredentials::NTLM_FLAG_TARGET_DOMAIN));
|
||||
assertTrue (msg2.challenge.size() == 8);
|
||||
assertTrue (msg2.target == "DOMAIN");
|
||||
|
||||
assertTrue (msg2.targetInfo.size() == 98);
|
||||
|
||||
assertTrue (msg2.challenge[0] == 0x01);
|
||||
assertTrue (msg2.challenge[1] == 0x23);
|
||||
assertTrue (msg2.challenge[7] == 0xef);
|
||||
|
||||
assertTrue (msg2.targetInfo[0] == 0x02);
|
||||
assertTrue (msg2.targetInfo[1] == 0x00);
|
||||
assertTrue (msg2.targetInfo[97] == 0x00);
|
||||
}
|
||||
|
||||
|
||||
void NTLMCredentialsTest::testFormatAuthenticateMessage()
|
||||
{
|
||||
const unsigned char LM[] = {
|
||||
0xc3, 0x37, 0xcd, 0x5c, 0xbd, 0x44, 0xfc, 0x97,
|
||||
0x82, 0xa6, 0x67, 0xaf, 0x6d, 0x42, 0x7c, 0x6d,
|
||||
0xe6, 0x7c, 0x20, 0xc2, 0xd3, 0xe7, 0x7c, 0x56
|
||||
};
|
||||
const unsigned char NTLM[] = {
|
||||
0x25, 0xa9, 0x8c, 0x1c, 0x31, 0xe8, 0x18, 0x47,
|
||||
0x46, 0x6b, 0x29, 0xb2, 0xdf, 0x46, 0x80, 0xf3,
|
||||
0x99, 0x58, 0xfb, 0x8c, 0x21, 0x3a, 0x9c, 0xc6
|
||||
};
|
||||
|
||||
NTLMCredentials::AuthenticateMessage msg3;
|
||||
msg3.flags = NTLMCredentials::NTLM_FLAG_NEGOTIATE_UNICODE | NTLMCredentials::NTLM_FLAG_NEGOTIATE_NTLM;
|
||||
msg3.target = "DOMAIN";
|
||||
msg3.username = "user";
|
||||
msg3.workstation = "WORKSTATION";
|
||||
msg3.lmResponse.assign(LM, LM + sizeof(LM));
|
||||
msg3.ntlmResponse.assign(NTLM, NTLM + sizeof(NTLM));
|
||||
|
||||
std::vector<unsigned char> msg3Buffer = NTLMCredentials::formatAuthenticateMessage(msg3);
|
||||
std::string msg3BufferHex = Poco::DigestEngine::digestToHex(msg3Buffer);
|
||||
|
||||
assertTrue (msg3BufferHex ==
|
||||
"4e544c4d5353500003000000180018004000000018001800"
|
||||
"580000000c000c0070000000080008007c00000016001600"
|
||||
"84000000000000009a00000001020000c337cd5cbd44fc97"
|
||||
"82a667af6d427c6de67c20c2d3e77c5625a98c1c31e81847"
|
||||
"466b29b2df4680f39958fb8c213a9cc644004f004d004100"
|
||||
"49004e00750073006500720057004f0052004b0053005400"
|
||||
"4100540049004f004e00"
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
void NTLMCredentialsTest::setUp()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void NTLMCredentialsTest::tearDown()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
CppUnit::Test* NTLMCredentialsTest::suite()
|
||||
{
|
||||
CppUnit::TestSuite* pSuite = new CppUnit::TestSuite("NTLMCredentialsTest");
|
||||
|
||||
CppUnit_addTest(pSuite, NTLMCredentialsTest, testNonce);
|
||||
CppUnit_addTest(pSuite, NTLMCredentialsTest, testPasswordHash);
|
||||
CppUnit_addTest(pSuite, NTLMCredentialsTest, testNTLMv2Hash);
|
||||
CppUnit_addTest(pSuite, NTLMCredentialsTest, testLMv2Response);
|
||||
CppUnit_addTest(pSuite, NTLMCredentialsTest, testNTLMv2Response);
|
||||
CppUnit_addTest(pSuite, NTLMCredentialsTest, testFormatNegotiateMessage);
|
||||
CppUnit_addTest(pSuite, NTLMCredentialsTest, testParseChallengeMessage);
|
||||
CppUnit_addTest(pSuite, NTLMCredentialsTest, testParseChallengeMessageWithTargetInfo);
|
||||
CppUnit_addTest(pSuite, NTLMCredentialsTest, testFormatAuthenticateMessage);
|
||||
|
||||
return pSuite;
|
||||
}
|
46
Net/testsuite/src/NTLMCredentialsTest.h
Normal file
46
Net/testsuite/src/NTLMCredentialsTest.h
Normal file
@ -0,0 +1,46 @@
|
||||
//
|
||||
// NTLMCredentialsTest.h
|
||||
//
|
||||
// Definition of the NTLMCredentialsTest class.
|
||||
//
|
||||
// Copyright (c) 2019, Applied Informatics Software Engineering GmbH.
|
||||
// and Contributors.
|
||||
//
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
//
|
||||
|
||||
|
||||
#ifndef NTLMCredentialsTest_INCLUDED
|
||||
#define NTLMCredentialsTest_INCLUDED
|
||||
|
||||
|
||||
#include "Poco/Net/Net.h"
|
||||
#include "CppUnit/TestCase.h"
|
||||
|
||||
|
||||
class NTLMCredentialsTest: public CppUnit::TestCase
|
||||
{
|
||||
public:
|
||||
NTLMCredentialsTest(const std::string& name);
|
||||
~NTLMCredentialsTest();
|
||||
|
||||
void testNonce();
|
||||
void testPasswordHash();
|
||||
void testNTLMv2Hash();
|
||||
void testLMv2Response();
|
||||
void testNTLMv2Response();
|
||||
void testFormatNegotiateMessage();
|
||||
void testParseChallengeMessage();
|
||||
void testParseChallengeMessageWithTargetInfo();
|
||||
void testFormatAuthenticateMessage();
|
||||
|
||||
void setUp();
|
||||
void tearDown();
|
||||
|
||||
static CppUnit::Test* suite();
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
|
||||
#endif // NTLMCredentialsTest_INCLUDED
|
Loading…
x
Reference in New Issue
Block a user