MeWrite Docs

SAML Authentication Failed

SAML認証でIdPとSP間の認証処理が失敗するエラー

概要

SAML Authentication Failed は、SAML(Security Assertion Markup Language)を使用したシングルサインオン(SSO)で、Identity Provider(IdP)とService Provider(SP)間の認証処理が失敗した際に発生するエラーです。

エラーメッセージ

SAML Response validation failed: Signature validation failed
SAML authentication error: InResponseTo attribute does not match the original request
SAML Response is not valid: NotBefore condition not met
Error: Unable to validate SAML assertion - Certificate mismatch

原因

  1. 証明書の不一致: IdPの署名証明書とSPに登録された証明書が異なる
  2. 時刻のずれ: IdPとSPのサーバー時刻がずれている(NotBefore/NotOnOrAfter条件の違反)
  3. メタデータの不正: IdPまたはSPのメタデータが古い、または不正
  4. ACS URLの不一致: Assertion Consumer Service URLが正しく設定されていない
  5. NameID フォーマットの不一致: IdPとSPで期待するNameIDフォーマットが異なる
  6. リプレイ攻撃検知: 同じSAMLレスポンスが再送された

解決策

1. 証明書の確認と更新

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# IdP のメタデータから証明書を取得
curl -s https://idp.example.com/metadata | \
  xmllint --xpath '//*[local-name()="X509Certificate"]/text()' -

# 証明書の有効期限を確認
echo "-----BEGIN CERTIFICATE-----
MIIDxTCCAq2gAwIBAgIJAJC1...
-----END CERTIFICATE-----" | openssl x509 -text -noout | grep -A2 "Validity"

# 証明書のフィンガープリントを確認
openssl x509 -in idp-cert.pem -fingerprint -noout

2. サーバー時刻の同期(NTP)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
# 現在のサーバー時刻を確認
date -u

# NTP同期の状態を確認
timedatectl status

# NTP を有効化
sudo timedatectl set-ntp true

# 手動で時刻同期
sudo ntpdate pool.ntp.org

# chronyd の場合
sudo chronyc tracking
sudo chronyc makestep

3. Python(python3-saml)の設定

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# settings.json
{
    "sp": {
        "entityId": "https://app.example.com/saml/metadata",
        "assertionConsumerService": {
            "url": "https://app.example.com/saml/acs",
            "binding": "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
        },
        "NameIDFormat": "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress"
    },
    "idp": {
        "entityId": "https://idp.example.com/entity",
        "singleSignOnService": {
            "url": "https://idp.example.com/sso",
            "binding": "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
        },
        "x509cert": "MIIDxTCCAq2gAwIBAgIJAJC1..."
    },
    "security": {
        "wantAssertionsSigned": true,
        "wantNameIdEncrypted": false,
        "relaxDestinationValidation": false
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
from onelogin.saml2.auth import OneLogin_Saml2_Auth

def saml_acs(request):
    auth = OneLogin_Saml2_Auth(request, custom_base_path=SAML_FOLDER)
    auth.process_response()
    errors = auth.get_errors()

    if errors:
        # エラーの詳細を確認
        print(f"SAML Errors: {errors}")
        print(f"Last error reason: {auth.get_last_error_reason()}")
        return handle_saml_error(errors)

    if not auth.is_authenticated():
        return redirect('/login?error=saml_auth_failed')

    # 認証成功
    attributes = auth.get_attributes()
    name_id = auth.get_nameid()
    return create_session(name_id, attributes)

4. 時刻のずれに対する許容設定

1
2
3
4
5
6
7
# python3-saml: 時刻のずれを許容
{
    "security": {
        "wantAssertionsSigned": true,
        "rejectedTimes": false  # 時刻検証を無効化(デバッグ用のみ)
    }
}
1
2
3
# Ruby (ruby-saml): 許容秒数を設定
settings = OneLogin::RubySaml::Settings.new
settings.allowed_clock_drift = 30  # 30秒の時刻ずれを許容

5. メタデータの確認

1
2
3
4
5
6
7
8
# SP メタデータの確認
curl https://app.example.com/saml/metadata | xmllint --format -

# 確認すべき項目:
# - entityID が正しいか
# - ACS URL が正しいか
# - 証明書が最新か
# - NameIDFormat が IdP と一致しているか

6. デバッグ手順

1
2
3
4
5
# SAML Response をデコード(Base64)
echo "PHNhbWxwOlJlc3Bv..." | base64 -d | xmllint --format -

# SAML Response の署名を検証
xmlsec1 --verify --pubkey-cert-pem idp-cert.pem --id-attr:ID urn:oasis:names:tc:SAML:2.0:assertion:Assertion saml-response.xml
1
2
3
4
5
6
7
8
# ブラウザの開発者ツールで SAML Response を確認
# 1. Network タブを開く
# 2. ACS URL へのPOSTリクエストを探す
# 3. Form Data の SAMLResponse をコピー
# 4. Base64 デコードして確認
import base64
saml_response = "PHNhbWxwOlJlc3Bv..."
print(base64.b64decode(saml_response).decode('utf-8'))

関連エラー

Security の他のエラー

最終更新: 2026-02-03