Skip to main content

A python client for .Net NegotiateStream

Project description

jetblack-negotiate-stream

A Python client for .Net NegotiateStream. It supports single sign on (SSO) and encryption.

This was tested using Python 3.8 on Windows 11.

Installation

Install from pypi.

pip install jetblack-negotiate-stream

Example

The following programs provide a simple echo server in C# and client in Python.

Client

This is an example of a Python client using the synchronous NegotiateStream class. Note the call to authenticate_as_client before reading and writing.

import socket

from jetblack_negotiate_stream import NegotiateStream

def main():
    hostname = socket.gethostname()
    port = 8181

    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
        sock.connect((hostname, port))

        stream = NegotiateStream(hostname, sock)

        # Do the client side negotiate handshake.
        stream.authenticate_as_client()

        for data in (b'first line', b'second line', b'third line'):
            # All reads and writes are encrypted.
            stream.write(data)
            response = stream.read()
            print("Received: ", response)

if __name__ == '__main__':
    main()

Async Client

This program uses NegotiateStreamAsync which is simply an asynchronous version of the NegotiateStream class demonstrated above.

import asyncio
import socket

from jetblack_negotiate_stream import NegotiateStreamAsync

async def main():
    hostname = socket.gethostname()
    port = 8181

    reader, writer = await asyncio.open_connection(hostname, port)

    stream = NegotiateStreamAsync(hostname, reader, writer)

    await stream.authenticate_as_client()
    for data in (b'first line', b'second line', b'third line'):
        stream.write(data)
        await stream.drain()
        response = await stream.read()
        print("Received: ", response)

    stream.close()
    await stream.wait_closed()

if __name__ == '__main__':
    asyncio.run(main())

Alternative Async Client

The following client follows the patterns demonstrated in the asyncio library using open_negotiate_stream. This follows the conventions of the asyncio open_connection function. The negotiation happens before the function returns, resulting in cleaner code.

import asyncio
import socket

from jetblack_negotiate_stream import open_negotiate_stream

async def main():
    hostname = socket.gethostname()
    port = 8181

    # Following the same pattern as asyncio.open_connection.
    reader, writer = await open_negotiate_stream(hostname, port)

    for data in (b'first line', b'second line', b'third line'):
        writer.write(data)
        await writer.drain()
        response = await reader.read()
        print("Received: ", response)

    writer.close()
    await writer.wait_closed()

if __name__ == '__main__':
    asyncio.run(main())

Server

Here is a trivial C# echo server for the clients.

using System;
using System.Net;
using System.Net.Security;
using System.Net.Sockets;
using System.Text;

namespace NegotiateStreamServer
{
    internal class Program
    {
        static void Main(string[] args)
        {
            var listener = new TcpListener(IPAddress.Any, 8181);
            listener.Start();

            while (true)
            {
                Console.WriteLine("Listening ...");
                var client = listener.AcceptTcpClient();

                try
                {
                    Console.WriteLine("... Client connected.");

                    Console.WriteLine("Authenticating...");
                    var stream = new NegotiateStream(client.GetStream(), false);
                    stream.AuthenticateAsServer();

                    Console.WriteLine(
                        "... {0} authenticated using {1}",
                        stream.RemoteIdentity.Name,
                        stream.RemoteIdentity.AuthenticationType);

                    var buf = new byte[4096];
                    for (var i = 0; i < 3; ++i)
                    {
                        var bytesRead = stream.Read(buf, 0, buf.Length);
                        var message = Encoding.UTF8.GetString(buf, 0, bytesRead);
                        Console.WriteLine(message);
                        stream.Write(buf, 0, bytesRead);
                    }
                    stream.Close();
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.ToString());
                }
            }
        }
    }
}

Acknowledgements

The library uses the pyspnego library, and takes many ideas from net.tcp-proxy.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

jetblack-negotiate-stream-0.2.2.tar.gz (7.8 kB view hashes)

Uploaded Source

Built Distribution

jetblack_negotiate_stream-0.2.2-py3-none-any.whl (9.8 kB view hashes)

Uploaded Python 3

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page