wellcomecollection / platform

Wellcome Collection Digital Platform
https://developers.wellcomecollection.org/
MIT License
48 stars 10 forks source link

Improve mechanism for obtaining STS tokens #3753

Closed kenoir closed 5 years ago

kenoir commented 5 years ago

Using a chrome plugin is less than ideal

Some specific issues:

alexwlchan commented 5 years ago

I had a play with the Azure CLI this evening.

You can log in with:

$ az login --allow-no-subscriptions

It gives you a login token; you open a browser and enter that token.

Then you can get the tenant ID:

$ az account show
{
  "environmentName": "AzureCloud",
  "id": "{ID}",
  "isDefault": true,
  "name": "N/A(tenant level account)",
  "state": "Enabled",
  "tenantId": "{TENANT_ID}",
  "user": {
    "name": "A.Chan@wellcome.ac.uk",
    "type": "user"
  }
}

The SSO SAML request format is documented here: https://docs.microsoft.com/en-us/azure/active-directory/develop/single-sign-on-saml-protocol#authnrequest

Based on that and the Node tool, you take a blob of XML like this:

<samlp:AuthnRequest xmlns="urn:oasis:names:tc:SAML:2.0:metadata" ID="id{id}" Version="2.0" IssueInstant="{dt.datetime.now().isoformat()}" IsPassive="false" AssertionConsumerServiceURL="https://signin.aws.amazon.com/saml" xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol">
    <Issuer xmlns="urn:oasis:names:tc:SAML:2.0:assertion">{appIdUri}</Issuer>
    <samlp:NameIDPolicy Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress"></samlp:NameIDPolicy>
</samlp:AuthnRequest>

zlib compress it, base64 encode and then fire at an Azure URL:

https://login.microsoftonline.com/{TENANT_ID}/saml2?SAMLRequest={SAML_REQUEST}

If it can authenticate you, then I think we're in business.

Possible useful pieces:

Right now I get an error whenever I fire XML into Azure:

AADSTS750016: Parameter 'SAMLRequest' must be unique in HTTP SAML message.

But there might be a thread worth tugging on there.

alexwlchan commented 5 years ago

Okay, so this constructs a valid SAML request that logs you in if you go through the browser – I just can’t find a way to do it with the CLI:

# az login --allow-no-subscriptions

import base64
from urllib.parse import urlencode
import zlib

import requests

def deflate_and_base64_encode(value):
    compressor = zlib.compressobj(wbits=-15)

    return base64.b64encode(
        compressor.compress(value.encode("utf8")) + compressor.flush()
    )

import uuid

saml_param = deflate_and_base64_encode(
f'''<samlp:AuthnRequest xmlns="urn:oasis:names:tc:SAML:2.0:metadata" ID="{uuid.uuid4()}" Version="2.0" IssueInstant="2019-07-23T13:31:26.000Z" IsPassive="false" AssertionConsumerServiceURL="https://signin.aws.amazon.com/saml" xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol">
    <Issuer xmlns="urn:oasis:names:tc:SAML:2.0:assertion">https://signin.aws.amazon.com/saml#14</Issuer>
    <samlp:NameIDPolicy Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress"></samlp:NameIDPolicy>
</samlp:AuthnRequest>'''
)

params = urlencode({"SAMLRequest": saml_param})

url = "https://login.microsoftonline.com/$TENANTID/saml2?" + params

print(url)
alexwlchan commented 5 years ago

Also dumping this file here as a record of what the headless browser is doing.

ad_log.log

alexwlchan commented 5 years ago

Further investigation this evening: the only cookie it cares about is ESTSAUTH.

kenoir commented 5 years ago

Done?!

gtmtech commented 4 years ago

@alexwlchan did you get this working?

alexwlchan commented 4 years ago

@gtmtech I used https://github.com/alexwlchan/azure-aws-credentials for a while, and now we all use https://github.com/sportradar/aws-azure-login