AzureAD SAML SSOを使うときの SAMLRequestを生成する


前提

  • SAML初心者です
  • 全体的によくわかってないけれどやってみた結果をまとめてみました
  • ちょっと冗長です

経緯

  • AzureADをIDプロバイダ(IdP)、AWSをサービスプロバイダ(SP)として使う設定をします
  • Microsoftのチュートリアル に沿って設定しました
  • https://myapps.microsoft.com へアクセスし、Azureログインした上で、AWSアイコンをクリックすると、AWSへ設定したロールでアクセスできました

  • IdP側に各SPへのメニューがあるので、これで使えるのでまあ問題ないと思うのですが、サインオンしていない状態でSPにアクセスした場合はどうするのでしょう

調べる

  • サインオンしていない場合はIdPへリダイレクトするのが標準のようです
    • 実際そういうサービスはよく見かけます
    • 「SP-Initiated SSO」と言うようです
  • SP側から「AuthnRequest」を持ってIdPへリダイレクトするらしいです
  • 「AuthnRequest」ってなんでしょう...ありました シングル サインオンの SAML プロトコル
  • 必要な情報をXMLに詰め込んだモノみたいです。これをどうやって連携しつつIdPへリダイレクトするのでしょう...
  • IdPのsaml2受付URLへGETパラメータ SAMLRequest で指定するようです
    • https://idp.example.com/saml2?SAMLRequest=連携情報
  • GETパラメータにXMLそのまま載せられないですよね。どうするんだろう...
  • みつけました 「DeflateしてBase64エンコードしてURLエンコードする」難易度高いな...
  • Deflateは圧縮ですね.とりあえずpythonで試すので zlib でできそうです
  • 圧縮結果はバイナリなのでbase64でエンコードしてGETパラメータに乗せるのでURLエンコードするってことみたいです
  • 途中で気づいたのですが、Deflateは「ヘッダとチェックサムを含めない」という指定がありました
    • zlib.compress() だとヘッダ、チェックサムが付加されるので zlib.compressobj(wbits=) を使えば良さそうです

SP-Initiated SSOをやってみる

SAMLRequestに指定する文字列を生成する

  • AuthnRequest XML → Deflate → base64 → urlエンコードして、printしています
get_saml_request_param.py
import datetime
import zlib
from base64 import b64encode
from urllib import parse


def build_saml_request(request_id, issuer):
    issue_instant=datetime.datetime.utcnow().isoformat(timespec='milliseconds') # 現在時刻でいいかな
    return f'''
        <samlp:AuthnRequest xmlns="urn:oasis:names:tc:SAML:2.0:metadata"
            ID="{request_id}" Version="2.0" IsPassive="false" ForceAuthn="false"
            IssueInstant="{issue_instant}Z"
            xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol">
            <Issuer xmlns="urn:oasis:names:tc:SAML:2.0:assertion">{issuer}</Issuer>
        </samlp:AuthnRequest>'''

def deflate(text):
    compressobj = zlib.compressobj(wbits=-zlib.MAX_WBITS)
    return compressobj.compress(text.encode()) + compressobj.flush()

def get_saml_request_param(text):
    return parse.quote_plus(b64encode(deflate(text)))

saml_request_text = build_saml_request(
    request_id='id356a192b7913b04c54574d18c28d46e6395428ab', # 実際はハッシュとかにするのかな
    issuer='https://signin.aws.amazon.com/saml')             # Identifier (Entity ID)

print(get_saml_request_param(saml_request_text))
  • request_id は適当(ただし英字から始める必要あり)
  • issuer はAzure側のSAML SSO設定の値 Identifier (Entity ID) を使います

  • 実行すると下記のようになります
  • 出力された長い文字列を使います
$ python get_saml_request_param.py
jZFNS8NAEIbv%2FRVh7002X226JIWgCIUK0loP3qab0S5kd%2BPOpoq%2F3hotGgR1jgPvxzwzCT6nJNBtJ%2BreH8wGn3okH7zo1lDFemeEBVIkDGgk4aXY1tdrkYRcaPTQgAc2Cb7N6rJiqknzGcSLZD9fxOmeZzLP8nnWxIVMiiab4Sxd5FlSwJ4Fd%2BhIWVOxkyULVnQDROqIFXuAlpAFV9ZJHKqdV%2BM4oh5XhjwYf%2FLgCZ%2Fy%2BZRnt7wQeSziIuR5ej%2FW1ETo%2FCn0whrqNbotuqOSuNusK3bwviMRRaQejTIhPFMIGl6tCaXV0TupsdkASgwEf8fVOeuttC1bjvTlcIH7D3A492bLv1uW0YfxV1oZ%2Ffzz8g0%3D

ブラウザからテストしてみる

  • GETすればいいので、URLを組み立てればブラウザで確認できますね
  • Azure側のSAML SSO設定ページの Login URL を使います

URLはこんな感じです(もっと長い)

https://login.microsoftonline.com/cd91xxxxxxxxxxxx/saml2

上で生成したSAMLRequest文字列をパラメータとしてくっつけます
(キチントためすなら、さらに &RelayState= + SAML SSO設定ページの Relay State を指定します)

https://login.microsoftonline.com/cd91xxxxxxxxxxxx/saml2?SAMLRequest=jZFNS8NAEIbv%2F...snip...zz8g0%3D

できたURLをブラウザで開くと、MicrosoftアカウントのSigninページが表示されて、正常にサインインできれば、AWSのコンソール画面へ遷移します
(Microsoftアカウントへログイン済みであれば、Signinページは表示されず、AWSのコンソール画面へ遷移します)

エラー

  • AADSTS750054: SAMLRequest or SAMLResponse must be present as query string parameters in HTTP request for SAML Redirect binding.
    • GETパラメータに SAMLRequest=<request> が指定されていません
  • AADSTS750056: SAML message was not properly base64-encoded.
    • SAMLRequestパラメータの内容がbase64デコードできない内容になっています
    • base64エンコードがうまくできていないか、URLエンコードが悪いかもしれません
  • AADSTS7500529: The value '1......' is not a valid SAML ID. The ID must not begin with a number.
    • AuthnRequestXML内のID値は英字から始まる必要があります。数字から始めてはいけません
  • AADSTS700016: Application with identifier 'https://signin.aws.amazon.com/saml' was not found in the directory 'cd91xxxxxxxxxxxx'. This can happen if the application has not been installed by the administrator of the tenant or consented to by any user in the tenant. You may have sent your authentication request to the wrong tenant.
    • AuthnRequestで指定したIssuerと一致する設定がありません。Azure SAML SSO設定の Identifier (Entity ID) を確認します

リンク

下記ページを参照させていただき、助けられました。ありがとうございます