Hello,

i try to run a socket server in a domain network. At first i am using the DEMO from win32-package. If i start server and client on one computer under my username, all works fine. Also the connection to another computer works perfectly. But if i run the server with my username and a colleague will connect to my server, i get authentication failure. All Usernames are Domain-Member. One has local Administrator rights and the other one is standard windows user.
Running environment is python 2.7.2 win32 on windows7 64bit platform.

We also tested Kerberos, like

'socket_server.py server --package=Kerberos' # on Server side
'socket_server.py client --package=Kerberos --target-spn=RestrictedKrbHost/COMPUTERNAME.local # on client side, where COMPUTERNAME.local represent the Computername in FQDN notation, where the Server is running


All works fine, if Client and Server running under the same Username. Connecting to server for all other Domainusers will force an authentication-error on Serverside.


I tried starting server on my laptop, which has noch Domain-connection. All usernames are locally.
'root' = local Administrator
'froemer' = local user

socket_server.py client # as user froemer
socket_server.py client # as user root

The output is that, what i excpected

#############
Running test server...
The server is running as user root
Having conversation with client as user froemer
Client sent: 'Hello'
Client sent: 'from'
Client sent: 'the'
Client sent: 'client'
The server is back to user root
#############

Is there a more special way on running a socket-server like this one in a domain environment?



--#--#--#--#--#--#--#--#--#--#--#--#--#--#--#--#--#--#--#--#--#--#--#--#--#--#--

"""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 sys
import struct
import SocketServer
import win32api
import httplib
import traceback

import win32security
import sspi, sspicon

import optparse # sorry, this demo needs 2.3+

options = None # set to optparse object.

def GetUserName():
    try:
        return win32api.GetUserName()
    except win32api.error, 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, 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(("", options.port), None)
    print "Running test server..."
    s.serve_forever()

def sspi_client():
    c = httplib.HTTPConnection(options.host, 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.
                           """)
    parser.add_option("", "--host", action="store", default="localhost",
                      help="the host to connect - default is localhost")

    options, args = parser.parse_args()
    try:
        options.port = int(options.port)
    except (ValueError, TypeError):
        parser.error("--port must be an integer")

    try:
        options.host = str(options.host)
    except (ValueError, TypeError):
        parser.error("--host must be valid hostname")

    try:
        try:
            if not args:
                serve()
                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:
            raw_input("Press enter to continue")
_______________________________________________
python-win32 mailing list
python-win32@python.org
http://mail.python.org/mailman/listinfo/python-win32

Reply via email to