~ren/magentasso-test

41eddc560b942a2acb374b611d3809abaee10f82 — Lauren Jenkinson 10 months ago fba6539 main
Pull in `magentasso` from the external Git repository
6 files changed, 7 insertions(+), 180 deletions(-)

M Pipfile
M Pipfile.lock
D magentasso_test/magentasso/__init__.py
D magentasso_test/magentasso/request.py
D magentasso_test/magentasso/response.py
M magentasso_test/sso.py
M Pipfile => Pipfile +1 -0
@@ 9,6 9,7 @@ black = "*"
[packages]
flask = "*"
python-dotenv = "*"
magentasso = {git = "https://git.sr.ht/~ren/magentasso-py", ref = "main"}

[requires]
python_version = "3.8"

M Pipfile.lock => Pipfile.lock +5 -1
@@ 1,7 1,7 @@
{
    "_meta": {
        "hash": {
            "sha256": "196016bdb972164dd012daf5bbcab66cdc862862e49e0cd36e60bc67dd25a89e"
            "sha256": "a2dbdb2ef889cd73fe39f5e7e6565392487c2c660b3f4a67bfab1773e18a731b"
        },
        "pipfile-spec": 6,
        "requires": {


@@ 48,6 48,10 @@
            "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
            "version": "==2.11.2"
        },
        "magentasso": {
            "git": "https://git.sr.ht/~ren/magentasso-py",
            "ref": "5b2c27574893e602d4a8a6267594d2fb5b1c483b"
        },
        "markupsafe": {
            "hashes": [
                "sha256:00bc623926325b26bb9605ae9eae8a215691f33cae5df11ca5424f06f2d1f473",

D magentasso_test/magentasso/__init__.py => magentasso_test/magentasso/__init__.py +0 -2
@@ 1,2 0,0 @@
from .request import MagentaRequest
from .response import MagentaResponse

D magentasso_test/magentasso/request.py => magentasso_test/magentasso/request.py +0 -98
@@ 1,98 0,0 @@
import base64
import hmac
import json
import random
from urllib.parse import urlencode, urljoin


class MagentaRequest:
    def __init__(self, client_id, client_secret, nonce, scopes, callback_url):
        self.client_id = client_id

        self.client_secret = client_secret
        if not isinstance(client_secret, bytes):
            self.client_secret = base64.b32decode(client_secret.upper())

        self.nonce = nonce
        if nonce is None:
            self.nonce = random.randint(10000000, 99999999)

        self.scopes = scopes
        if not isinstance(scopes, list):
            self.scopes = [
                scopes,
            ]

        self.callback_url = callback_url

    def sign(self):
        data = {
            "client_id": self.client_id,
            "nonce": self.nonce,
            "scopes": self.scopes,
            "callback_url": self.callback_url,
        }

        payload = json.dumps(data).encode("utf-8")
        payload = base64.urlsafe_b64encode(payload)
        signature = hmac.digest(self.client_secret, payload, "sha256")
        signature = base64.urlsafe_b64encode(signature)

        return (payload, signature)

    def begin_url(self, magenta_base):
        payload, signature = self.sign()
        params = {
            "client": self.client_id,
            "payload": payload,
            "signature": signature,
        }

        params = urlencode(params)

        url = urljoin(magenta_base, f"/sso/begin?{params}")
        return url

    @classmethod
    def verify(cls, payload, signature, client_secret):
        if not isinstance(client_secret, bytes):
            client_secret = base64.b32decode(client_secret.upper())

        if not isinstance(signature, bytes):
            signature = signature.encode("utf-8")

        if not isinstance(payload, bytes):
            payload = payload.encode("utf-8")

        signature_check = hmac.digest(client_secret, payload, "sha256")
        signature = base64.urlsafe_b64decode(signature)

        if signature != signature_check:
            raise ValueError("mismatching signatures")

        payload = base64.urlsafe_b64decode(payload)
        payload = json.loads(payload.decode("utf-8"))

        scopes = payload["scopes"]
        if not isinstance(scopes, list):
            scopes = [
                scopes,
            ]

        output = cls(
            payload["client_id"],
            client_secret,
            payload["nonce"],
            scopes,
            payload["callback_url"],
        )

        return output

    def __repr__(self):
        return "MagentaRequest(client_id=%r nonce=%r scopes=%r callback_url=%r)" % (
            self.client_id,
            self.nonce,
            self.scopes,
            self.callback_url,
        )

D magentasso_test/magentasso/response.py => magentasso_test/magentasso/response.py +0 -78
@@ 1,78 0,0 @@
import base64
import hmac
import json

from urllib.parse import urlencode


class MagentaResponse:
    def __init__(self, client_id, client_secret, nonce, user_data, scope_data):
        self.client_id = client_id

        self.client_secret = client_secret
        if not isinstance(client_secret, bytes):
            self.client_secret = base64.b32decode(client_secret.upper())

        self.nonce = nonce
        self.user_data = user_data
        self.scope_data = scope_data

    def sign(self):
        data = {
            "client_id": self.client_id,
            "nonce": self.nonce,
            "user_data": self.user_data,
            "scope_data": self.scope_data,
        }

        payload = json.dumps(data).encode("utf-8")
        payload = base64.urlsafe_b64encode(payload)
        signature = hmac.digest(self.client_secret, payload, "sha256")
        signature = base64.urlsafe_b64encode(signature)

        return (payload, signature)

    def callback_query(self):
        payload, signature = self.sign()
        params = {
            "payload": payload,
            "signature": signature,
        }

        return urlencode(params)

    @classmethod
    def verify(cls, payload, signature, client_secret):
        if not isinstance(client_secret, bytes):
            client_secret = base64.b32decode(client_secret.upper())

        if not isinstance(signature, bytes):
            signature = signature.encode("utf-8")

        if not isinstance(payload, bytes):
            payload = payload.encode("utf-8")

        signature_check = hmac.digest(client_secret, payload, "sha256")
        signature = base64.urlsafe_b64decode(signature)

        if signature != signature_check:
            raise ValueError("mismatching signatures")

        payload = base64.urlsafe_b64decode(payload)
        payload = json.loads(payload.decode("utf-8"))

        output = cls(
            payload["client_id"],
            client_secret,
            payload["nonce"],
            payload["user_data"],
            payload["scope_data"],
        )

        return output

    def __repr__(self):
        return "MagentaResponse(client_id=%r nonce=%r)" % (
            self.client_id,
            self.nonce,
        )

M magentasso_test/sso.py => magentasso_test/sso.py +1 -1
@@ 1,5 1,6 @@
import random

from magentasso import MagentaRequest, MagentaResponse
from flask import (
    Blueprint,
    current_app,


@@ 11,7 12,6 @@ from flask import (
    url_for,
    redirect,
)
from magentasso_test.magentasso import MagentaRequest, MagentaResponse

sso = Blueprint("sso", __name__)