jetblack-negotiate-stream


Namejetblack-negotiate-stream JSON
Version 0.1.0 PyPI version JSON
download
home_pagehttps://github.com/rob-blackbourn/jetblack-negotiate-stream
SummaryA python client for .Net NegotiateStream
upload_time2022-12-21 14:59:13
maintainer
docs_urlNone
authorRob Blackbourn
requires_python>=3.8,<4.0
licenseApache-2.0
keywords
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # jetblack-negotiate-stream

A Python client for .Net [NegotiateStream](https://learn.microsoft.com/en-us/dotnet/api/system.net.security.negotiatestream).
It supports single sign on (SSO) and encryption.

This was tested using Python 3.8 on Windows 11.

## Installation

Install from pypi.

```bash
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.

```python
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 a synchronous version of the `NegotiateStream` class demonstrated above.

```python
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. 

```python
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.

```csharp
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](https://github.com/jborean93/pyspnego) library,
and takes many ideas from [net.tcp-proxy](https://github.com/ernw/net.tcp-proxy).

            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/rob-blackbourn/jetblack-negotiate-stream",
    "name": "jetblack-negotiate-stream",
    "maintainer": "",
    "docs_url": null,
    "requires_python": ">=3.8,<4.0",
    "maintainer_email": "",
    "keywords": "",
    "author": "Rob Blackbourn",
    "author_email": "rob.blackbourn@gmail.com",
    "download_url": "https://files.pythonhosted.org/packages/a1/8a/874d79fd0b61aa0573b3006380ef0bd07a7ee1bec96826c9238ccfb2727d/jetblack_negotiate_stream-0.1.0.tar.gz",
    "platform": null,
    "description": "# jetblack-negotiate-stream\n\nA Python client for .Net [NegotiateStream](https://learn.microsoft.com/en-us/dotnet/api/system.net.security.negotiatestream).\nIt supports single sign on (SSO) and encryption.\n\nThis was tested using Python 3.8 on Windows 11.\n\n## Installation\n\nInstall from pypi.\n\n```bash\npip install jetblack-negotiate-stream\n```\n\n## Example\n\nThe following programs provide a simple echo server in C# and client in Python.\n\n### Client\n\nThis is an example of a Python client using the synchronous `NegotiateStream` class. Note the call to `authenticate_as_client` before reading and writing.\n\n```python\nimport socket\n\nfrom jetblack_negotiate_stream import NegotiateStream\n\ndef main():\n    hostname = socket.gethostname()\n    port = 8181\n\n    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:\n        sock.connect((hostname, port))\n\n        stream = NegotiateStream(hostname, sock)\n\n        # Do the client side negotiate handshake.\n        stream.authenticate_as_client()\n\n        for data in (b'first line', b'second line', b'third line'):\n            # All reads and writes are encrypted.\n            stream.write(data)\n            response = stream.read()\n            print(\"Received: \", response)\n\nif __name__ == '__main__':\n    main()\n```\n\n### Async Client\n\nThis program uses `NegotiateStreamAsync` which is simply a synchronous version of the `NegotiateStream` class demonstrated above.\n\n```python\nimport asyncio\nimport socket\n\nfrom jetblack_negotiate_stream import NegotiateStreamAsync\n\nasync def main():\n    hostname = socket.gethostname()\n    port = 8181\n\n    reader, writer = await asyncio.open_connection(hostname, port)\n\n    stream = NegotiateStreamAsync(hostname, reader, writer)\n\n    await stream.authenticate_as_client()\n    for data in (b'first line', b'second line', b'third line'):\n        stream.write(data)\n        await stream.drain()\n        response = await stream.read()\n        print(\"Received: \", response)\n\n    stream.close()\n    await stream.wait_closed()\n\nif __name__ == '__main__':\n    asyncio.run(main())\n```\n\n### Alternative Async Client\n\nThe following client follows the patterns demonstrated in the asyncio library using `open_negotiate_stream`. This follows\nthe conventions of the asyncio `open_connection` function. The negotiation happens before the function returns, resulting in cleaner code. \n\n```python\nimport asyncio\nimport socket\n\nfrom jetblack_negotiate_stream import open_negotiate_stream\n\nasync def main():\n    hostname = socket.gethostname()\n    port = 8181\n\n    # Following the same pattern as asyncio.open_connection.\n    reader, writer = await open_negotiate_stream(hostname, port)\n\n    for data in (b'first line', b'second line', b'third line'):\n        writer.write(data)\n        await writer.drain()\n        response = await reader.read()\n        print(\"Received: \", response)\n\n    writer.close()\n    await writer.wait_closed()\n\nif __name__ == '__main__':\n    asyncio.run(main())\n```\n\n### Server\n\nHere is a trivial C# echo server for the clients.\n\n```csharp\nusing System;\nusing System.Net;\nusing System.Net.Security;\nusing System.Net.Sockets;\nusing System.Text;\n\nnamespace NegotiateStreamServer\n{\n    internal class Program\n    {\n        static void Main(string[] args)\n        {\n            var listener = new TcpListener(IPAddress.Any, 8181);\n            listener.Start();\n\n            while (true)\n            {\n                Console.WriteLine(\"Listening ...\");\n                var client = listener.AcceptTcpClient();\n\n                try\n                {\n                    Console.WriteLine(\"... Client connected.\");\n\n                    Console.WriteLine(\"Authenticating...\");\n                    var stream = new NegotiateStream(client.GetStream(), false);\n                    stream.AuthenticateAsServer();\n\n                    Console.WriteLine(\n                        \"... {0} authenticated using {1}\",\n                        stream.RemoteIdentity.Name,\n                        stream.RemoteIdentity.AuthenticationType);\n\n                    var buf = new byte[4096];\n                    for (var i = 0; i < 3; ++i)\n                    {\n                        var bytesRead = stream.Read(buf, 0, buf.Length);\n                        var message = Encoding.UTF8.GetString(buf, 0, bytesRead);\n                        Console.WriteLine(message);\n                        stream.Write(buf, 0, bytesRead);\n                    }\n                    stream.Close();\n                }\n                catch (Exception ex)\n                {\n                    Console.WriteLine(ex.ToString());\n                }\n            }\n        }\n    }\n}\n```\n\n## Acknowledgements\n\nThe library uses the [pyspnego](https://github.com/jborean93/pyspnego) library,\nand takes many ideas from [net.tcp-proxy](https://github.com/ernw/net.tcp-proxy).\n",
    "bugtrack_url": null,
    "license": "Apache-2.0",
    "summary": "A python client for .Net NegotiateStream",
    "version": "0.1.0",
    "split_keywords": [],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "md5": "41c7812d4cb7378bcb811983a8926123",
                "sha256": "32fe7f4db7eefd02db4770c6c161d85ed396221490f41a8b682280f1743bac03"
            },
            "downloads": -1,
            "filename": "jetblack_negotiate_stream-0.1.0-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "41c7812d4cb7378bcb811983a8926123",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.8,<4.0",
            "size": 7410,
            "upload_time": "2022-12-21T14:59:11",
            "upload_time_iso_8601": "2022-12-21T14:59:11.117469Z",
            "url": "https://files.pythonhosted.org/packages/a9/5a/74e0a75df7019952a8734160e09699565883b0b61a4a2df6152292251aa4/jetblack_negotiate_stream-0.1.0-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "md5": "417210b136dd2ba7086fbf50b27d9e17",
                "sha256": "be5e8fa9dc678e3564e4f41c02a7abc2870a915132fa5f9f2ff9d78b1a09abce"
            },
            "downloads": -1,
            "filename": "jetblack_negotiate_stream-0.1.0.tar.gz",
            "has_sig": false,
            "md5_digest": "417210b136dd2ba7086fbf50b27d9e17",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.8,<4.0",
            "size": 5650,
            "upload_time": "2022-12-21T14:59:13",
            "upload_time_iso_8601": "2022-12-21T14:59:13.214751Z",
            "url": "https://files.pythonhosted.org/packages/a1/8a/874d79fd0b61aa0573b3006380ef0bd07a7ee1bec96826c9238ccfb2727d/jetblack_negotiate_stream-0.1.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2022-12-21 14:59:13",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "github_user": "rob-blackbourn",
    "github_project": "jetblack-negotiate-stream",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": false,
    "lcname": "jetblack-negotiate-stream"
}
        
Elapsed time: 0.37418s