New upstream release.
Kali Janitor
2 years ago
7 | 7 | branches: |
8 | 8 | - master |
9 | 9 | |
10 | env: | |
11 | WINRM_USERNAME: pywinrm-test | |
12 | WINRM_PASSWORD: Password123! | |
10 | # env: | |
11 | # WINRM_USERNAME: pywinrm-test | |
12 | # WINRM_PASSWORD: Password123! | |
13 | 13 | |
14 | 14 | jobs: |
15 | 15 | test: |
27 | 27 | - 3.7 |
28 | 28 | - 3.8 |
29 | 29 | - 3.9 |
30 | - '3.10' | |
30 | 31 | - pypy-2.7 |
31 | 32 | - pypy-3.7 |
32 | 33 | arch: |
56 | 57 | python-version: ${{ matrix.python-version }} |
57 | 58 | architecture: ${{ matrix.arch }} |
58 | 59 | |
59 | - name: set up Windows integration tests | |
60 | if: startsWith(matrix.os, 'windows') | |
61 | shell: pwsh | |
62 | run: | | |
63 | Write-Host 'Create local admin user' | |
64 | $userParams = @{ | |
65 | Name = $env:WINRM_USERNAME | |
66 | Password = (ConvertTo-SecureString -AsPlainText -Force -String $env:WINRM_PASSWORD) | |
67 | AccountNeverExpires = $true | |
68 | PasswordNeverExpires = $true | |
69 | } | |
70 | $null = New-LocalUser @userParams | |
71 | Add-LocalGroupMember -Group Administrators -Member $userParams.Name | |
60 | # - name: Remove extra modules to speed up PowerShell startup module due to slow WinRM issue | |
61 | # if: startsWith(matrix.os, 'windows') | |
62 | # shell: bash | |
63 | # run: | | |
64 | # rm -rf "/c/Program Files/WindowsPowerShell/Modules/AWSPowerShell" | |
65 | # rm -rf "/c/Program Files/WindowsPowerShell/Modules/Microsoft.Graph*" | |
72 | 66 | |
73 | Write-Host 'Setting up WinRM settings' | |
74 | Enable-PSRemoting -Force -SkipNetworkProfileCheck | |
75 | Enable-WSManCredSSP -Role Server -Force | |
76 | Set-Item WSMan:\localhost\Service\Auth\Basic $true | |
77 | Set-Item WSMan:\localhost\Service\Auth\CredSSP $true | |
78 | Set-Item WSMan:\localhost\Service\AllowUnencrypted $true | |
67 | # - name: set up Windows integration tests | |
68 | # if: startsWith(matrix.os, 'windows') | |
69 | # shell: pwsh | |
70 | # run: | | |
71 | # Write-Host 'Create local admin user' | |
72 | # $userParams = @{ | |
73 | # Name = $env:WINRM_USERNAME | |
74 | # Password = (ConvertTo-SecureString -AsPlainText -Force -String $env:WINRM_PASSWORD) | |
75 | # AccountNeverExpires = $true | |
76 | # PasswordNeverExpires = $true | |
77 | # } | |
78 | # $null = New-LocalUser @userParams | |
79 | # Add-LocalGroupMember -Group Administrators -Member $userParams.Name | |
80 | ||
81 | # Write-Host 'Setting up WinRM settings' | |
82 | # Enable-PSRemoting -Force -SkipNetworkProfileCheck | |
83 | # Enable-WSManCredSSP -Role Server -Force | |
84 | # Set-Item WSMan:\localhost\Service\Auth\Basic $true | |
85 | # Set-Item WSMan:\localhost\Service\Auth\CredSSP $true | |
86 | # Set-Item WSMan:\localhost\Service\AllowUnencrypted $true | |
79 | 87 | |
80 | 88 | - name: set up Linux dependencies |
81 | 89 | if: startsWith(matrix.os, 'ubuntu') |
102 | 110 | if: startsWith(matrix.os, 'windows') |
103 | 111 | run: | |
104 | 112 | pytest -v --flake8 --cov=winrm --cov-report=term-missing winrm/tests/ |
105 | env: | |
106 | WINRM_TRANSPORT: basic | |
107 | WINRM_ENDPOINT: http://localhost:5985/wsman | |
113 | # env: | |
114 | # WINRM_TRANSPORT: basic | |
115 | # WINRM_ENDPOINT: http://localhost:5985/wsman | |
108 | 116 | |
109 | 117 | - name: upload coverage data |
110 | 118 | if: "!endsWith(matrix.python-version, '2.7')" # Uses an older coverals version that doesn't support GHA |
112 | 120 | env: |
113 | 121 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} |
114 | 122 | |
115 | - name: run integration with NTLM | |
116 | if: startsWith(matrix.os, 'windows') | |
117 | run: | | |
118 | Set-Item WSMan:\localhost\Service\AllowUnencrypted $false | |
119 | py.test -v winrm/tests/test_integration_protocol.py winrm/tests/test_integration_session.py | |
120 | env: | |
121 | WINRM_TRANSPORT: ntlm | |
122 | WINRM_ENDPOINT: http://localhost:5985/wsman | |
123 | # - name: run integration with NTLM | |
124 | # if: startsWith(matrix.os, 'windows') | |
125 | # run: | | |
126 | # Set-Item WSMan:\localhost\Service\AllowUnencrypted $false | |
127 | # py.test -v winrm/tests/test_integration_protocol.py winrm/tests/test_integration_session.py | |
128 | # env: | |
129 | # WINRM_TRANSPORT: ntlm | |
130 | # WINRM_ENDPOINT: http://localhost:5985/wsman | |
123 | 131 | |
124 | - name: run integration with CredSSP | |
125 | if: startsWith(matrix.os, 'windows') | |
126 | run: | | |
127 | Set-Item WSMan:\localhost\Service\AllowUnencrypted $false | |
128 | py.test -v winrm/tests/test_integration_protocol.py winrm/tests/test_integration_session.py | |
129 | env: | |
130 | WINRM_TRANSPORT: credssp | |
131 | WINRM_ENDPOINT: http://localhost:5985/wsman | |
132 | # - name: run integration with CredSSP | |
133 | # if: startsWith(matrix.os, 'windows') | |
134 | # run: | | |
135 | # Set-Item WSMan:\localhost\Service\AllowUnencrypted $false | |
136 | # py.test -v winrm/tests/test_integration_protocol.py winrm/tests/test_integration_session.py | |
137 | # env: | |
138 | # WINRM_TRANSPORT: credssp | |
139 | # WINRM_ENDPOINT: http://localhost:5985/wsman |
0 | 0 | # Changelog |
1 | ||
2 | ### Version 0.4.3 | |
3 | - Fix invalid regex escape sequences. | |
4 | - Decoding CLIXML failures for `run_ps` will create a `UserWarning` rather than printing the warning. | |
5 | - Remove usage of deprecated Python API to support Python 3.11 | |
1 | 6 | |
2 | 7 | ### Version 0.4.2 |
3 | 8 | - Dropped Python 3.5 from support matrix as it is EOL. |
0 | pywinrm (0.4.2-0kali1) UNRELEASED; urgency=low | |
0 | pywinrm (0.4.3-0kali1) UNRELEASED; urgency=low | |
1 | 1 | |
2 | 2 | * New upstream release. |
3 | * New upstream release. | |
3 | 4 | |
4 | -- Kali Janitor <[email protected]> Wed, 26 Jan 2022 01:48:02 -0000 | |
5 | -- Kali Janitor <[email protected]> Mon, 16 May 2022 02:53:28 -0000 | |
5 | 6 | |
6 | 7 | pywinrm (0.4.1-0kali2) kali-dev; urgency=medium |
7 | 8 |
0 | 0 | # this assumes the base requirements have been satisfied via setup.py |
1 | # pin specific versions to keep things more stable over time; only pin sub-packages if necessary | |
2 | pytest==4.4.2 | |
3 | pytest-cov==2.7.1 | |
1 | pytest | |
2 | pytest-cov | |
4 | 3 | pytest-flake8==1.0.7 |
5 | mock==3.0.5 | |
4 | mock |
0 | 0 | from setuptools import setup, find_packages |
1 | 1 | |
2 | __version__ = '0.4.2' | |
2 | __version__ = '0.4.3' | |
3 | 3 | project_name = 'pywinrm' |
4 | 4 | |
5 | 5 | # PyPi supports only reStructuredText, so pandoc should be installed |
22 | 22 | license='MIT license', |
23 | 23 | packages=find_packages(), |
24 | 24 | package_data={'winrm.tests': ['*.ps1']}, |
25 | install_requires=['xmltodict', 'requests>=2.9.1', 'requests_ntlm>=0.3.0', 'six'], | |
25 | install_requires=['xmltodict', 'requests>=2.9.1', 'requests_ntlm>=1.1.0', 'six'], | |
26 | 26 | extras_require={ |
27 | 27 | 'credssp': ['requests-credssp>=1.0.0'], |
28 | 28 | 'kerberos:sys_platform=="win32"': ['winkerberos>=0.5.0'], |
43 | 43 | 'Programming Language :: Python :: 3.7', |
44 | 44 | 'Programming Language :: Python :: 3.8', |
45 | 45 | 'Programming Language :: Python :: 3.9', |
46 | 'Programming Language :: Python :: 3.10', | |
46 | 47 | 'Programming Language :: Python :: Implementation :: PyPy', |
47 | 48 | 'Topic :: Software Development :: Libraries :: Python Modules', |
48 | 49 | 'Topic :: System :: Clustering', |
1 | 1 | import re |
2 | 2 | from base64 import b64encode |
3 | 3 | import xml.etree.ElementTree as ET |
4 | import warnings | |
4 | 5 | |
5 | 6 | from winrm.protocol import Protocol |
6 | 7 | |
77 | 78 | new_msg += s.text.replace("_x000D__x000A_", "\n") |
78 | 79 | except Exception as e: |
79 | 80 | # if any of the above fails, the msg was not true xml |
80 | # print a warning and return the orignal string | |
81 | # TODO do not print, raise user defined error instead | |
82 | print("Warning: there was a problem converting the Powershell" | |
83 | " error message: %s" % (e)) | |
81 | # print a warning and return the original string | |
82 | warnings.warn( | |
83 | "There was a problem converting the Powershell error " | |
84 | "message: %s" % (e)) | |
84 | 85 | else: |
85 | 86 | # if new_msg was populated, that's our error message |
86 | 87 | # otherwise the original error message will be used |
103 | 104 | @staticmethod |
104 | 105 | def _build_url(target, transport): |
105 | 106 | match = re.match( |
106 | '(?i)^((?P<scheme>http[s]?)://)?(?P<host>[0-9a-z-_.]+)(:(?P<port>\d+))?(?P<path>(/)?(wsman)?)?', target) # NOQA | |
107 | r'(?i)^((?P<scheme>http[s]?)://)?(?P<host>[0-9a-z-_.]+)(:(?P<port>\d+))?(?P<path>(/)?(wsman)?)?', target) # NOQA | |
107 | 108 | scheme = match.group('scheme') |
108 | 109 | if not scheme: |
109 | 110 | # TODO do we have anything other than HTTP/HTTPS |
91 | 91 | """ |
92 | 92 | Takes in the encrypted response from the server and decrypts it |
93 | 93 | |
94 | :param response: The response that needs to be decrytped | |
94 | :param response: The response that needs to be decrypted | |
95 | 95 | :return: The unencrypted message from the server |
96 | 96 | """ |
97 | 97 | content_type = response.headers['Content-Type'] |
6 | 6 | |
7 | 7 | |
8 | 8 | class WinRMTransportError(Exception): |
9 | """WinRM errors specific to transport-level problems (unexpcted HTTP error codes, etc)""" | |
9 | """WinRM errors specific to transport-level problems (unexpected HTTP error codes, etc)""" | |
10 | 10 | |
11 | 11 | @property |
12 | 12 | def protocol(self): |
55 | 55 | Any other value will be considered the CA trust path to use. |
56 | 56 | @param string cert_pem: client authentication certificate file path in PEM format # NOQA |
57 | 57 | @param string cert_key_pem: client authentication certificate key file path in PEM format # NOQA |
58 | @param string server_cert_validation: whether server certificate should be validated on Python versions that suppport it; one of 'validate' (default), 'ignore' #NOQA | |
58 | @param string server_cert_validation: whether server certificate should be validated on Python versions that support it; one of 'validate' (default), 'ignore' #NOQA | |
59 | 59 | @param bool kerberos_delegation: if True, TGT is sent to target server to allow multiple hops # NOQA |
60 | 60 | @param int read_timeout_sec: maximum seconds to wait before an HTTP connect/read times out (default 30). This value should be slightly higher than operation_timeout_sec, as the server can block *at least* that long. # NOQA |
61 | 61 | @param int operation_timeout_sec: maximum allowed time in seconds for any single wsman HTTP operation (default 20). Note that operation timeouts while receiving output (the only wsman operation that should take any significant time, and where these timeouts are expected) will be silently retried indefinitely. # NOQA |
435 | 435 | @param string command_id: The command id on the remote machine. |
436 | 436 | See #run_command |
437 | 437 | #@return [Hash] Returns a Hash with a key :exitcode and :data. |
438 | Data is an Array of Hashes where the cooresponding key | |
438 | Data is an Array of Hashes where the corresponding key | |
439 | 439 | # is either :stdout or :stderr. The reason it is in an Array so so |
440 | we can get the output in the order it ocurrs on | |
440 | we can get the output in the order it occurs on | |
441 | 441 | # the console. |
442 | 442 | """ |
443 | 443 | stdout_buffer, stderr_buffer = [], [] |
0 | import pytest | |
1 | ||
0 | 2 | from winrm import Session |
1 | 3 | |
2 | 4 | |
77 | 79 | expected = msg |
78 | 80 | actual = s._clean_error_msg(msg) |
79 | 81 | assert actual == expected |
82 | ||
83 | ||
84 | def test_decode_clixml_invalid_xml(): | |
85 | s = Session('windows-host.example.com', auth=('john.smith', 'secret')) | |
86 | msg = b'#< CLIXML\r\n<in >dasf<?dsfij>' | |
87 | ||
88 | with pytest.warns(UserWarning, match="There was a problem converting the Powershell error message"): | |
89 | actual = s._clean_error_msg(msg) | |
90 | ||
91 | assert actual == msg |
0 | 0 | from __future__ import unicode_literals |
1 | 1 | import sys |
2 | 2 | import os |
3 | import inspect | |
4 | 3 | import requests |
5 | 4 | import requests.auth |
6 | 5 | import warnings |
227 | 226 | |
228 | 227 | if self.auth_method == 'kerberos': |
229 | 228 | if not HAVE_KERBEROS: |
230 | raise WinRMError("requested auth method is kerberos, but requests_kerberos is not installed") | |
231 | ||
232 | man_args = dict( | |
229 | raise WinRMError("requested auth method is kerberos, but pykerberos is not installed") | |
230 | ||
231 | session.auth = HTTPKerberosAuth( | |
233 | 232 | mutual_authentication=REQUIRED, |
234 | ) | |
235 | opt_args = dict( | |
236 | 233 | delegate=self.kerberos_delegation, |
237 | 234 | force_preemptive=True, |
238 | 235 | principal=self.username, |
241 | 238 | service=self.service, |
242 | 239 | send_cbt=self.send_cbt |
243 | 240 | ) |
244 | kerb_args = self._get_args(man_args, opt_args, HTTPKerberosAuth.__init__) | |
245 | session.auth = HTTPKerberosAuth(**kerb_args) | |
246 | 241 | encryption_available = hasattr(session.auth, 'winrm_encryption_available') and session.auth.winrm_encryption_available |
247 | 242 | elif self.auth_method in ['certificate', 'ssl']: |
248 | 243 | if self.auth_method == 'ssl' and not self.cert_pem and not self.cert_key_pem: |
256 | 251 | elif self.auth_method == 'ntlm': |
257 | 252 | if not HAVE_NTLM: |
258 | 253 | raise WinRMError("requested auth method is ntlm, but requests_ntlm is not installed") |
259 | man_args = dict( | |
254 | ||
255 | session.auth = HttpNtlmAuth( | |
260 | 256 | username=self.username, |
261 | password=self.password | |
257 | password=self.password, | |
258 | send_cbt=self.send_cbt, | |
262 | 259 | ) |
263 | opt_args = dict( | |
264 | send_cbt=self.send_cbt | |
265 | ) | |
266 | ntlm_args = self._get_args(man_args, opt_args, HttpNtlmAuth.__init__) | |
267 | session.auth = HttpNtlmAuth(**ntlm_args) | |
268 | 260 | # check if requests_ntlm has the session_security attribute available for encryption |
269 | 261 | encryption_available = hasattr(session.auth, 'session_security') |
270 | 262 | # TODO: ssl is not exactly right here- should really be client_cert |
274 | 266 | if not HAVE_CREDSSP: |
275 | 267 | raise WinRMError("requests auth method is credssp, but requests-credssp is not installed") |
276 | 268 | |
277 | man_args = dict( | |
269 | session.auth = HttpCredSSPAuth( | |
278 | 270 | username=self.username, |
279 | password=self.password | |
280 | ) | |
281 | opt_args = dict( | |
271 | password=self.password, | |
282 | 272 | disable_tlsv1_2=self.credssp_disable_tlsv1_2, |
283 | 273 | auth_mechanism=self.credssp_auth_mechanism, |
284 | 274 | minimum_version=self.credssp_minimum_version |
285 | 275 | ) |
286 | credssp_args = self._get_args(man_args, opt_args, HttpCredSSPAuth.__init__) | |
287 | session.auth = HttpCredSSPAuth(**credssp_args) | |
288 | 276 | encryption_available = True |
289 | 277 | else: |
290 | 278 | raise WinRMError("unsupported auth method: %s" % self.auth_method) |
354 | 342 | else: |
355 | 343 | response_text = response.content |
356 | 344 | return response_text |
357 | ||
358 | def _get_args(self, mandatory_args, optional_args, function): | |
359 | argspec = set(inspect.getargspec(function).args) | |
360 | function_args = dict() | |
361 | for name, value in mandatory_args.items(): | |
362 | if name in argspec: | |
363 | function_args[name] = value | |
364 | else: | |
365 | raise Exception("Function %s does not contain mandatory arg " | |
366 | "%s, check installed version with pip list" | |
367 | % (str(function), name)) | |
368 | ||
369 | for name, value in optional_args.items(): | |
370 | if name in argspec: | |
371 | function_args[name] = value | |
372 | else: | |
373 | warnings.warn("Function %s does not contain optional arg %s, " | |
374 | "check installed version with pip list" | |
375 | % (str(function), name)) | |
376 | ||
377 | return function_args |
97 | 97 | else: |
98 | 98 | # There's no need to re-compile this EVERY time it is called. Compile |
99 | 99 | # it once and you won't have the performance hit of the compilation. |
100 | regex = re.compile('(?:.*,)*\s*Negotiate\s*([^,]*),?', re.I) | |
100 | regex = re.compile(r'(?:.*,)*\s*Negotiate\s*([^,]*),?', re.I) | |
101 | 101 | _negotiate_value.regex = regex |
102 | 102 | |
103 | 103 | authreq = response.headers.get('www-authenticate', None) |