Bump cherrypy from 18.8.0 to 18.9.0 (#2266)

* Bump cherrypy from 18.8.0 to 18.9.0

Bumps [cherrypy](https://github.com/cherrypy/cherrypy) from 18.8.0 to 18.9.0.
- [Changelog](https://github.com/cherrypy/cherrypy/blob/main/CHANGES.rst)
- [Commits](https://github.com/cherrypy/cherrypy/compare/v18.8.0...v18.9.0)

---
updated-dependencies:
- dependency-name: cherrypy
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

* Update cherrypy==18.9.0

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: JonnyWong16 <9099342+JonnyWong16@users.noreply.github.com>

[skip ci]
This commit is contained in:
dependabot[bot] 2024-03-24 15:25:44 -07:00 committed by GitHub
commit faef9a94c4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
673 changed files with 159850 additions and 11583 deletions

View file

@ -0,0 +1,160 @@
"""
Fetches a URL from a web-server supporting NTLM authentication
eg, IIS.
If no arguments are specified, a default of http://localhost/localstart.asp
is used. This script does follow simple 302 redirections, so pointing at the
root of an IIS server is should work.
"""
import http.client # sorry, this demo needs 2.3+
import optparse
import urllib.error
import urllib.parse
import urllib.request
from base64 import decodestring, encodestring
from sspi import ClientAuth
options = None # set to optparse options object
def open_url(host, url):
h = http.client.HTTPConnection(host)
# h.set_debuglevel(9)
h.putrequest("GET", url)
h.endheaders()
resp = h.getresponse()
print("Initial response is", resp.status, resp.reason)
body = resp.read()
if resp.status == 302: # object moved
url = "/" + resp.msg["location"]
resp.close()
h.putrequest("GET", url)
h.endheaders()
resp = h.getresponse()
print("After redirect response is", resp.status, resp.reason)
if options.show_headers:
print("Initial response headers:")
for name, val in list(resp.msg.items()):
print(" %s: %s" % (name, val))
if options.show_body:
print(body)
if resp.status == 401:
# 401: Unauthorized - here is where the real work starts
auth_info = None
if options.user or options.domain or options.password:
auth_info = options.user, options.domain, options.password
ca = ClientAuth("NTLM", auth_info=auth_info)
auth_scheme = ca.pkg_info["Name"]
data = None
while 1:
err, out_buf = ca.authorize(data)
data = out_buf[0].Buffer
# Encode it as base64 as required by HTTP
auth = encodestring(data).replace("\012", "")
h.putrequest("GET", url)
h.putheader("Authorization", auth_scheme + " " + auth)
h.putheader("Content-Length", "0")
h.endheaders()
resp = h.getresponse()
if options.show_headers:
print("Token dance headers:")
for name, val in list(resp.msg.items()):
print(" %s: %s" % (name, val))
if err == 0:
break
else:
if resp.status != 401:
print("Eeek - got response", resp.status)
cl = resp.msg.get("content-length")
if cl:
print(repr(resp.read(int(cl))))
else:
print("no content!")
assert resp.status == 401, resp.status
assert not resp.will_close, "NTLM is per-connection - must not close"
schemes = [
s.strip() for s in resp.msg.get("WWW-Authenticate", "").split(",")
]
for scheme in schemes:
if scheme.startswith(auth_scheme):
data = decodestring(scheme[len(auth_scheme) + 1 :])
break
else:
print(
"Could not find scheme '%s' in schemes %r" % (auth_scheme, schemes)
)
break
resp.read()
print("Final response status is", resp.status, resp.reason)
if resp.status == 200:
# Worked!
# Check we can read it again without re-authenticating.
if resp.will_close:
print(
"EEEK - response will close, but NTLM is per connection - it must stay open"
)
body = resp.read()
if options.show_body:
print("Final response body:")
print(body)
h.putrequest("GET", url)
h.endheaders()
resp = h.getresponse()
print("Second fetch response is", resp.status, resp.reason)
if options.show_headers:
print("Second response headers:")
for name, val in list(resp.msg.items()):
print(" %s: %s" % (name, val))
resp.read(int(resp.msg.get("content-length", 0)))
elif resp.status == 500:
print("Error text")
print(resp.read())
else:
if options.show_body:
cl = resp.msg.get("content-length")
print(resp.read(int(cl)))
if __name__ == "__main__":
parser = optparse.OptionParser(description=__doc__)
parser.add_option(
"",
"--show-body",
action="store_true",
help="print the body of each response as it is received",
)
parser.add_option(
"",
"--show-headers",
action="store_true",
help="print the headers of each response as it is received",
)
parser.add_option("", "--user", action="store", help="The username to login with")
parser.add_option(
"", "--password", action="store", help="The password to login with"
)
parser.add_option("", "--domain", action="store", help="The domain to login to")
options, args = parser.parse_args()
if not args:
print("Run with --help for usage details")
args = ["http://localhost/localstart.asp"]
for url in args:
scheme, netloc, path, params, query, fragment = urllib.parse.urlparse(url)
if (scheme != "http") or params or query or fragment:
parser.error("Scheme must be http, URL must be simple")
print("Opening '%s' from '%s'" % (path, netloc))
r = open_url(netloc, path)

View file

@ -0,0 +1,72 @@
# A demo of basic SSPI authentication.
# There is a 'client' context and a 'server' context - typically these will
# be on different machines (here they are in the same process, but the same
# concepts apply)
import sspi
import sspicon
import win32api
import win32security
def lookup_ret_code(err):
for k, v in list(sspicon.__dict__.items()):
if k[0:6] in ("SEC_I_", "SEC_E_") and v == err:
return k
"""
pkg_name='Kerberos'
sspiclient=SSPIClient(pkg_name, win32api.GetUserName(), ## target spn is ourself
None, None, ## use none for client name and authentication information for current context
## u'username', (u'username',u'domain.com',u'passwd'),
sspicon.ISC_REQ_INTEGRITY|sspicon.ISC_REQ_SEQUENCE_DETECT|sspicon.ISC_REQ_REPLAY_DETECT| \
sspicon.ISC_REQ_DELEGATE|sspicon.ISC_REQ_CONFIDENTIALITY|sspicon.ISC_REQ_USE_SESSION_KEY)
sspiserver=SSPIServer(pkg_name, None,
sspicon.ASC_REQ_INTEGRITY|sspicon.ASC_REQ_SEQUENCE_DETECT|sspicon.ASC_REQ_REPLAY_DETECT| \
sspicon.ASC_REQ_DELEGATE|sspicon.ASC_REQ_CONFIDENTIALITY|sspicon.ASC_REQ_STREAM|sspicon.ASC_REQ_USE_SESSION_KEY)
"""
pkg_name = "NTLM"
# Setup the 2 contexts.
sspiclient = sspi.ClientAuth(pkg_name)
sspiserver = sspi.ServerAuth(pkg_name)
# Perform the authentication dance, each loop exchanging more information
# on the way to completing authentication.
sec_buffer = None
while 1:
err, sec_buffer = sspiclient.authorize(sec_buffer)
err, sec_buffer = sspiserver.authorize(sec_buffer)
if err == 0:
break
# The server can now impersonate the client. In this demo the 2 users will
# always be the same.
sspiserver.ctxt.ImpersonateSecurityContext()
print("Impersonated user: ", win32api.GetUserNameEx(win32api.NameSamCompatible))
sspiserver.ctxt.RevertSecurityContext()
print("Reverted to self: ", win32api.GetUserName())
pkg_size_info = sspiclient.ctxt.QueryContextAttributes(sspicon.SECPKG_ATTR_SIZES)
# Now sign some data
msg = "some data to be encrypted ......"
sigsize = pkg_size_info["MaxSignature"]
sigbuf = win32security.PySecBufferDescType()
sigbuf.append(win32security.PySecBufferType(len(msg), sspicon.SECBUFFER_DATA))
sigbuf.append(win32security.PySecBufferType(sigsize, sspicon.SECBUFFER_TOKEN))
sigbuf[0].Buffer = msg
sspiclient.ctxt.MakeSignature(0, sigbuf, 1)
sspiserver.ctxt.VerifySignature(sigbuf, 1)
# And finally encrypt some.
trailersize = pkg_size_info["SecurityTrailer"]
encbuf = win32security.PySecBufferDescType()
encbuf.append(win32security.PySecBufferType(len(msg), sspicon.SECBUFFER_DATA))
encbuf.append(win32security.PySecBufferType(trailersize, sspicon.SECBUFFER_TOKEN))
encbuf[0].Buffer = msg
sspiclient.ctxt.EncryptMessage(0, encbuf, 1)
print("Encrypted data:", repr(encbuf[0].Buffer))
sspiserver.ctxt.DecryptMessage(encbuf, 1)
print("Unencrypted data:", encbuf[0].Buffer)

View file

@ -0,0 +1,201 @@
"""A sample socket server and client using SSPI authentication and encryption.
You must run with either 'client' or 'server' as arguments. A server must be
running before a client can connect.
To use with Kerberos you should include in the client options
--target-spn=username, where 'username' is the user under which the server is
being run.
Running either the client or server as a different user can be informative.
A command-line such as the following may be useful:
`runas /user:{user} {fqp}\python.exe {fqp}\socket_server.py --wait client|server`
{fqp} should specify the relevant fully-qualified path names.
To use 'runas' with Kerberos, the client program will need to
specify --target-spn with the username under which the *server* is running.
See the SSPI documentation for more details.
"""
import http.client # sorry, this demo needs 2.3+
import optparse
import socketserver
import struct
import traceback
import sspi
import win32api
import win32security
options = None # set to optparse object.
def GetUserName():
try:
return win32api.GetUserName()
except win32api.error as details:
# Seeing 'access denied' errors here for non-local users (presumably
# without permission to login locally). Get the fully-qualified
# username, although a side-effect of these permission-denied errors
# is a lack of Python codecs - so printing the Unicode value fails.
# So just return the repr(), and avoid codecs completely.
return repr(win32api.GetUserNameEx(win32api.NameSamCompatible))
# Send a simple "message" over a socket - send the number of bytes first,
# then the string. Ditto for receive.
def _send_msg(s, m):
s.send(struct.pack("i", len(m)))
s.send(m)
def _get_msg(s):
size_data = s.recv(struct.calcsize("i"))
if not size_data:
return None
cb = struct.unpack("i", size_data)[0]
return s.recv(cb)
class SSPISocketServer(socketserver.TCPServer):
def __init__(self, *args, **kw):
socketserver.TCPServer.__init__(self, *args, **kw)
self.sa = sspi.ServerAuth(options.package)
def verify_request(self, sock, ca):
# Do the sspi auth dance
self.sa.reset()
while 1:
data = _get_msg(sock)
if data is None:
return False
try:
err, sec_buffer = self.sa.authorize(data)
except sspi.error as details:
print("FAILED to authorize client:", details)
return False
if err == 0:
break
_send_msg(sock, sec_buffer[0].Buffer)
return True
def process_request(self, request, client_address):
# An example using the connection once it is established.
print("The server is running as user", GetUserName())
self.sa.ctxt.ImpersonateSecurityContext()
try:
print("Having conversation with client as user", GetUserName())
while 1:
# we need to grab 2 bits of data - the encrypted data, and the
# 'key'
data = _get_msg(request)
key = _get_msg(request)
if data is None or key is None:
break
data = self.sa.decrypt(data, key)
print("Client sent:", repr(data))
finally:
self.sa.ctxt.RevertSecurityContext()
self.close_request(request)
print("The server is back to user", GetUserName())
def serve():
s = SSPISocketServer(("localhost", options.port), None)
print("Running test server...")
s.serve_forever()
def sspi_client():
c = http.client.HTTPConnection("localhost", options.port)
c.connect()
# Do the auth dance.
ca = sspi.ClientAuth(options.package, targetspn=options.target_spn)
data = None
while 1:
err, out_buf = ca.authorize(data)
_send_msg(c.sock, out_buf[0].Buffer)
if err == 0:
break
data = _get_msg(c.sock)
print("Auth dance complete - sending a few encryted messages")
# Assume out data is sensitive - encrypt the message.
for data in "Hello from the client".split():
blob, key = ca.encrypt(data)
_send_msg(c.sock, blob)
_send_msg(c.sock, key)
c.sock.close()
print("Client completed.")
if __name__ == "__main__":
parser = optparse.OptionParser("%prog [options] client|server", description=__doc__)
parser.add_option(
"",
"--package",
action="store",
default="NTLM",
help="The SSPI package to use (eg, Kerberos) - default is NTLM",
)
parser.add_option(
"",
"--target-spn",
action="store",
help="""The target security provider name to use. The
string contents are security-package specific. For
example, 'Kerberos' or 'Negotiate' require the server
principal name (SPN) (ie, the username) of the remote
process. For NTLM this must be blank.""",
)
parser.add_option(
"",
"--port",
action="store",
default="8181",
help="The port number to use (default=8181)",
)
parser.add_option(
"",
"--wait",
action="store_true",
help="""Cause the program to wait for input just before
terminating. Useful when using via runas to see
any error messages before termination.
""",
)
options, args = parser.parse_args()
try:
options.port = int(options.port)
except (ValueError, TypeError):
parser.error("--port must be an integer")
try:
try:
if not args:
args = [""]
if args[0] == "client":
sspi_client()
elif args[0] == "server":
serve()
else:
parser.error(
"You must supply 'client' or 'server' - " "use --help for details"
)
except KeyboardInterrupt:
pass
except SystemExit:
pass
except:
traceback.print_exc()
finally:
if options.wait:
input("Press enter to continue")

View file

@ -0,0 +1,41 @@
# Demonstrates how to validate a password.
# See also MSKB article Q180548
#
# To use with Kerberos you need to jump through the 'targetspn' hoops.
import sys
import win32security
from sspi import ClientAuth, ServerAuth
def validate(username, password, domain=""):
auth_info = username, domain, password
ca = ClientAuth("NTLM", auth_info=auth_info)
sa = ServerAuth("NTLM")
data = err = None
while err != 0:
err, data = ca.authorize(data)
err, data = sa.authorize(data)
# If we get here without exception, we worked!
if __name__ == "__main__":
if len(sys.argv) not in [2, 3, 4]:
print("Usage: %s username [password [domain]]" % (__file__,))
sys.exit(1)
# password and domain are optional!
password = None
if len(sys.argv) >= 3:
password = sys.argv[2]
domain = ""
if len(sys.argv) >= 4:
domain = sys.argv[3]
try:
validate(sys.argv[1], password, domain)
print("Validated OK")
except win32security.error as details:
hr, func, msg = details
print("Validation failed: %s (%d)" % (msg, hr))