def send(self, message): hostname = get_hostname(self.endpoint) if self.session is None: self.session = self._build_session() # need to send an initial blank message to setup the security # context required for encryption if self.wrap_required: request = requests.Request('POST', self.endpoint, data=None) prep_request = self.session.prepare_request(request) self._send_request(prep_request) protocol = WinRMEncryption.SPNEGO if isinstance(self.session.auth, HttpCredSSPAuth): protocol = WinRMEncryption.CREDSSP elif self.session.auth.contexts[ hostname].response_auth_header == 'kerberos': # When Kerberos (not Negotiate) was used, we need to send a special protocol value and not SPNEGO. protocol = WinRMEncryption.KERBEROS self.encryption = WinRMEncryption( self.session.auth.contexts[hostname], protocol) log.debug("Sending message: %s" % message) # for testing, keep commented out # self._test_messages.append({"request": message.decode('utf-8'), # "response": None}) headers = self.session.headers if self.wrap_required: content_type, payload = self.encryption.wrap_message(message) type_header = '%s;protocol="%s";boundary="Encrypted Boundary"' \ % (content_type, self.encryption.protocol) headers.update({ 'Content-Type': type_header, 'Content-Length': str(len(payload)), }) else: payload = message headers['Content-Type'] = "application/soap+xml;charset=UTF-8" request = requests.Request('POST', self.endpoint, data=payload, headers=headers) prep_request = self.session.prepare_request(request) return self._send_request(prep_request)
def send(self, message: bytes) -> bytes: hostname = get_hostname(self.endpoint) if self.session is None: self.session = self._build_session() # need to send an initial blank message to setup the security # context required for encryption if self.wrap_required: request = requests.Request("POST", self.endpoint, data=None) prep_request = self.session.prepare_request(request) self._send_request(prep_request) protocol = WinRMEncryption.SPNEGO if isinstance(self.session.auth, HttpCredSSPAuth): protocol = WinRMEncryption.CREDSSP elif self.session.auth.contexts[hostname].response_auth_header == "kerberos": # type: ignore[union-attr] # This should not happen # When Kerberos (not Negotiate) was used, we need to send a special protocol value and not SPNEGO. protocol = WinRMEncryption.KERBEROS self.encryption = WinRMEncryption(self.session.auth.contexts[hostname], protocol) # type: ignore[union-attr] # This should not happen if log.isEnabledFor(logging.DEBUG): log.debug("Sending message: %s" % message.decode("utf-8")) # for testing, keep commented out # self._test_messages.append({"request": message.decode('utf-8'), # "response": None}) headers = self.session.headers if self.wrap_required: content_type, payload = self.encryption.wrap_message(message) # type: ignore[union-attr] # This should not happen protocol = self.encryption.protocol if self.encryption else WinRMEncryption.SPNEGO type_header = '%s;protocol="%s";boundary="Encrypted Boundary"' % (content_type, protocol) headers.update( { "Content-Type": type_header, "Content-Length": str(len(payload)), } ) else: payload = message headers["Content-Type"] = "application/soap+xml;charset=UTF-8" request = requests.Request("POST", self.endpoint, data=payload, headers=headers) prep_request = self.session.prepare_request(request) return self._send_request(prep_request)
def handle_401(self, response, **kwargs): host = get_hostname(response.url) if self.send_cbt: cbt_app_data = HTTPNegotiateAuth._get_cbt_data(response) auth_hostname = self.hostname_override or host context, token_gen, out_token = get_auth_context( self.username, self.password, self.auth_provider, cbt_app_data, auth_hostname, self.service, self.delegate, self.wrap_required ) self.contexts[host] = context while not context.complete or out_token is not None: # consume content and release the original connection to allow the # new request to reuse the same one. response.content response.raw.release_conn() # create a request with the Negotiate token present request = response.request.copy() log.debug("Sending http request with new auth token") self._set_auth_token(request, out_token, "Negotiate") # send the request with the auth token and get the response response = response.connection.send(request, **kwargs) # attempt to retrieve the auth token response in_token = self._get_auth_token(response, self._regex) # break if there was no token received from the host and return the # last response if in_token in [None, b""]: log.debug("Did not receive a http response with an auth " "response, stopping authentication process") break out_token = token_gen.send(in_token) return response
def send(self, message): hostname = get_hostname(self.endpoint) if self.session is None: self.session = self._build_session() # need to send an initial blank message to setup the security # context required for encryption if self.wrap_required: request = requests.Request('POST', self.endpoint, data=None) prep_request = self.session.prepare_request(request) self._send_request(prep_request, hostname) log.debug("Sending message: %s" % message) # for testing, keep commented out # self._test_messages.append({"request": message.decode('utf-8'), # "response": None}) headers = self.session.headers if self.wrap_required: content_type, payload = self.encryption.wrap_message( message, hostname) type_header = '%s;protocol="%s";boundary="Encrypted Boundary"' \ % (content_type, self.encryption.protocol) headers.update({ 'Content-Type': type_header, 'Content-Length': str(len(payload)), }) else: payload = message headers['Content-Type'] = "application/soap+xml;charset=UTF-8" request = requests.Request('POST', self.endpoint, data=payload, headers=headers) prep_request = self.session.prepare_request(request) return self._send_request(prep_request, hostname)
def handle_401(self, response, **kwargs): response_auth_header = kwargs.pop('_pypsrp_auth_provider') response_auth_header_l = response_auth_header.lower() auth_provider = self.auth_provider if response_auth_header_l != self.auth_provider: if self.auth_provider == 'negotiate': auth_provider = response_auth_header_l elif response_auth_header_l != 'negotiate': raise ValueError( "Server responded with the auth protocol '%s' which is incompatible with the " "specified auth_provider '%s'" % (response_auth_header, auth_provider)) host = get_hostname(response.url) auth_hostname = self.hostname_override or host cbt = None if self.send_cbt: cbt_app_data = HTTPNegotiateAuth._get_cbt_data(response) if cbt_app_data: cbt = spnego.channel_bindings.GssChannelBindings( application_data=cbt_app_data) context_req = spnego.ContextReq.default if self.delegate: context_req |= spnego.ContextReq.delegate spnego_options = spnego.NegotiateOptions.wrapping_winrm if self.wrap_required else 0 context = spnego.client(self.username, self.password, hostname=auth_hostname, service=self.service, channel_bindings=cbt, context_req=context_req, protocol=auth_provider, options=spnego_options) self.contexts[host] = context out_token = context.step() while not context.complete or out_token is not None: # consume content and release the original connection to allow the # new request to reuse the same one. response.content response.raw.release_conn() # create a request with the Negotiate token present request = response.request.copy() log.debug("Sending http request with new auth token") self._set_auth_token(request, out_token, response_auth_header) # send the request with the auth token and get the response response = response.connection.send(request, **kwargs) # attempt to retrieve the auth token response in_token = self._get_auth_token(response, self._regex) # break if there was no token received from the host and return the # last response if in_token in [None, b""]: log.debug( "Did not receive a http response with an auth response, stopping authentication process" ) break out_token = context.step(in_token) # This is used by the message encryption to decide the MIME protocol. setattr(context, 'response_auth_header', response_auth_header_l) return response
def test_get_hostname(url, expected): assert expected == get_hostname(url)