Salesforce シングルサインオン(SSO)実装ガイド:技術アーキテクト向け解説


背景と適用シナリオ

現代のエンタープライズ環境では、従業員は日々の業務で多数のクラウドアプリケーションを利用しています。Salesforceもその中心的な存在の一つですが、アプリケーションごとに異なるIDとパスワードを管理することは、ユーザーにとって大きな負担となり、パスワードの使い回しといったセキュリティリスクを増大させます。また、IT管理者にとっても、ユーザーの入社・退社に伴うアカウント管理は煩雑な作業です。

Single Sign-On (SSO)(シングルサインオン)は、この課題を解決するための認証メカニズムです。SSOを導入することで、ユーザーは一度の認証(例えば、自社のポータルサイトへのログイン)で、許可された全てのアプリケーション(Salesforceを含む)にシームレスにアクセスできるようになります。これにより、以下のメリットがもたらされます。

  • ユーザーエクスペリエンスの向上: 複数のパスワードを覚える必要がなくなり、アプリケーションへのアクセスが迅速かつ容易になります。
  • セキュリティの強化: 認証を一元管理することで、多要素認証(MFA)の強制や、より強固なパスワードポリシーの適用が容易になります。退職者のアカウントもIDプロバイダー側で無効化するだけで、連携する全てのサービスへのアクセスを一度に遮断できます。
  • 管理コストの削減: パスワードリセットに関する問い合わせが減少し、ユーザープロビジョニング(アカウントの作成・更新)を自動化できるため、IT管理者の運用負荷が大幅に軽減されます。

適用シナリオとしては、「企業の従業員が、社内の認証システム(Active Directoryなど)を用いてSalesforceにログインする」といったケースが最も一般的です。これにより、企業は認証情報を自社の管理下に置き、一貫したセキュリティポリシーを適用できます。


原理説明

SalesforceにおけるSSOは、主に2つの標準プロトコル、SAMLOpenID Connect を利用して実現されます。どちらのプロトコルも、認証を行う「IDプロバイダー」と、サービスを提供する「サービスプロバイダー」間の信頼関係に基づいて動作します。

SAML (Security Assertion Markup Language)

SAML(サムル)は、エンタープライズ向けのSSOで最も広く利用されているXMLベースの標準規格です。SAMLのフローには、主に2つの役割が登場します。

  • Identity Provider (IdP)(IDプロバイダー): ユーザーを認証し、そのユーザーに関する情報(アサーション)を提供するシステムです。例:Microsoft Azure AD, Okta, ADFS。
  • Service Provider (SP)(サービスプロバイダー): ユーザーがアクセスしようとしているアプリケーションです。この場合、SalesforceがSPとなります。

SAML認証フロー(SP-Initiated Flow):

  1. ユーザーがSalesforceのログインページにアクセスします。
  2. Salesforce (SP) は、ユーザーをIdPの認証ページにリダイレクトします。
  3. ユーザーはIdPに対して認証情報(ID/パスワードなど)を入力し、認証を受けます。
  4. 認証が成功すると、IdPはユーザー情報を含んだデジタル署名付きのSAML Assertion(SAMLアサーション)を生成し、ブラウザ経由でSalesforceに送り返します。
  5. SalesforceはSAMLアサーションの署名を検証し、内容が正当であればユーザーを識別してログインセッションを確立します。

OpenID Connect

OpenID Connectは、OAuth 2.0プロトコルを基盤とした、よりモダンな認証プロトコルです。特に、モバイルアプリやWebアプリケーションでの利用に適しています。SAMLと同様に、信頼関係に基づく役割が存在します。

  • OpenID Provider (OP): IdPに相当し、ユーザーを認証します。例:Google, Facebook, Salesforce。
  • Relying Party (RP): SPに相当し、OPの認証情報を信頼して利用するアプリケーションです。

OpenID Connectでは、認証の証として ID Token というJSON Web Token (JWT) 形式のトークンが使用されます。このトークンには、ユーザーIDや認証時刻などの情報が含まれており、RPはこれを検証してユーザーをログインさせます。

Just-in-Time (JIT) プロビジョニング

Just-in-Time (JIT) Provisioning(ジャストインタイムプロビジョニング)は、SSOの強力な機能の一つです。これは、ユーザーがSSOを利用して初めてSalesforceにログインした際に、SAMLアサーション内の情報に基づいて、Salesforce上にユーザーアカウントを自動的に作成または更新する仕組みです。

例えば、SAMLアサーションにユーザーの氏名、メールアドレス、所属部署、役職などの属性情報を含めることで、Salesforceのユーザーオブジェクトに対応する項目を自動的に設定できます。これにより、管理者が手動でユーザーアカウントを作成する手間が省け、迅速なオンボーディングが可能になります。


サンプルコード

JITプロビジョニングを実装するには、Auth.SamlJitHandler インターフェースを実装したApexクラスを作成します。このクラスは、SAMLアサーションを受け取り、ユーザーの作成(createUser)または更新(updateUser)ロジックを定義します。以下は、Salesforce公式ドキュメントに基づくサンプルコードです。

// SAML JIT ハンドラのサンプルクラス
global class SamlJitHandler implements Auth.SamlJitHandler {

    // ユーザーを新規作成するロジック
    private class JitException extends Exception {}

    global User createUser(Id samlSsoProviderId, Id communityId, Id portalId,
        String federationIdentifier, Map<String, String> attributes, String assertion) {
        
        // 新規ユーザーオブジェクトを作成
        User u = new User();
        
        // SAMLアサーションから属性を取得してユーザー項目にマッピング
        // 'userAttributes' は、SSO設定で定義したカスタム属性名
        if(attributes.containsKey('userAttributes.FirstName')) {
            u.FirstName = attributes.get('userAttributes.FirstName');
        }
        if(attributes.containsKey('userAttributes.LastName')) {
            u.LastName = attributes.get('userAttributes.LastName');
        }
        if(attributes.containsKey('userAttributes.Email')) {
            u.Email = attributes.get('userAttributes.Email');
        }
        
        // ユーザー名、別名、ロケール、言語などの必須項目を設定
        String username = attributes.get('userAttributes.Username');
        // ユーザー名が一意であることを確認
        if (isUsernameTaken(username)) {
            // 必要に応じて、ユーザー名に一意のサフィックスを追加するなどの処理を実装
            System.debug('Username ' + username + ' is already taken.');
            throw new JitException('Username ' + username + ' is already taken, please try logging in with a different username');
        }
        u.Username = username;
        u.Alias = u.FirstName.substring(0,1) + u.LastName.substring(0, Math.min(4, u.LastName.length()));
        u.LocaleSidKey = 'ja_JP';
        u.LanguageLocaleKey = 'ja';
        u.EmailEncodingKey = 'ISO-2022-JP';
        u.TimeZoneSidKey = 'Asia/Tokyo';
        
        // プロファイルIDはハードコードではなく、カスタム設定やカスタムメタデータから動的に取得することを推奨
        Profile p = [SELECT Id FROM Profile WHERE Name = 'Standard User' LIMIT 1];
        u.ProfileId = p.Id;
        
        // ユーザーを挿入
        insert u;
        return u;
    }

    // 既存ユーザーを更新するロジック
    global void updateUser(Id userId, Id samlSsoProviderId, Id communityId, Id portalId,
        String federationIdentifier, Map<String, String> attributes, String assertion) {
        
        User u = new User(Id=userId);
        
        // 更新する項目をマッピング
        if(attributes.containsKey('userAttributes.FirstName')) {
            u.FirstName = attributes.get('userAttributes.FirstName');
        }
        if(attributes.containsKey('userAttributes.LastName')) {
            u.LastName = attributes.get('userAttributes.LastName');
        }
        if(attributes.containsKey('userAttributes.Email')) {
            u.Email = attributes.get('userAttributes.Email');
        }
        
        // ユーザーを更新
        update u;
    }

    private boolean isUsernameTaken(String username) {
        return ![SELECT count() FROM User WHERE Username = :username LIMIT 1].equals(0);
    }
}

コードの解説

  • createUser メソッド: SAMLアサーションを受け取り、新しい User sObjectを作成します。attributes マップからFirstName、LastName、Emailなどの値を取得し、対応する項目に設定します。プロファイルIDなど、組織固有の値は適切に設定する必要があります。
  • updateUser メソッド: 既存ユーザーがSSOでログインした際に呼び出されます。IdP側の情報が更新された場合(例:姓の変更)、Salesforce側のユーザー情報も同期できます。
  • エラーハンドリング: サンプルコードでは、ユーザー名が重複している場合に例外を投げています。実際のプロジェクトでは、より堅牢なエラーハンドリングとロギングを実装することが重要です。

注意事項

SSOを実装する際には、以下の点に注意が必要です。

権限と設定

  • 私のドメイン (My Domain): Salesforce組織で「私のドメイン」を有効化してリリースすることが、外部IdPとのSSO設定の前提条件です。
  • 必要な権限: SSO設定を行うユーザーには、「アプリケーションのカスタマイズ」および「シングルサインオン設定の管理」権限が必要です。

セキュリティに関する考慮事項

  • 証明書の管理: IdPの署名証明書は有効期限があります。証明書の有効期限が切れるとSSOログインが失敗するため、期限を監視し、計画的に更新するプロセスを確立する必要があります。
  • SAMLアサーションの暗号化: 必要に応じて、SAMLアサーション自体を暗号化することで、中間者攻撃(man-in-the-middle attack)に対するセキュリティをさらに強化できます。
  • リクエスト署名メソッド: SAMLリクエストの署名アルゴリズムには、安全性の高い「RSA-SHA256」を選択することを強く推奨します。

ユーザー管理とデプロビジョニング

  • デプロビジョニング: JITプロビジョニングはユーザーの作成と更新を行いますが、ユーザーの無効化(非アクティブ化)は行いません。従業員が退職してIdP側のアカウントが無効になっても、Salesforce上のアカウントはアクティブなまま残ってしまいます。これを放置すると、ライセンスの無駄遣いやセキュリティリスクに繋がります。
  • 対策: ユーザーのデプロビジョニングには、SCIM (System for Cross-domain Identity Management) プロトコルを利用するか、IdPの情報を定期的にAPI経由で取得し、Salesforceのユーザーを非アクティブ化するバッチ処理を実装するなどの対策が必要です。

テストとトラブルシューティング

  • サンドボックスでのテスト: 本番環境に展開する前に、必ずサンドボックス環境でSSO設定を構築し、様々なシナリオ(新規ユーザー、既存ユーザー、プロファイルが異なるユーザーなど)で徹底的にテストしてください。
  • SAMLアサーション検証: Salesforceの[設定] > [シングルサインオン設定]にある「SAML アサーション検証」機能は、IdPから送られてくるアサーションが正しいかどうかをデバッグするのに非常に役立ちます。
  • 管理者用ログインURLの確保: SSO設定に不備があった場合、全てのユーザーがログインできなくなる可能性があります。万一に備え、システム管理者は標準のログインURL(例: https://yourdomain.my.salesforce.com/?login)をブックマークし、ユーザー名とパスワードでのログイン方法を確保しておく必要があります。

まとめとベストプラクティス

Single Sign-On (SSO) は、Salesforceのセキュリティを強化し、ユーザーエクスペリエンスと管理効率を劇的に向上させるための不可欠な機能です。特に、中規模以上の組織においては、導入が強く推奨されます。実装を成功させるためには、プロトコルの原理を理解し、計画的に導入を進めることが重要です。

以下に、SSO実装のベストプラクティスをまとめます。

  • プロトコルの選定: 企業の既存認証基盤との連携が主目的であればSAMLを、モダンなWeb/モバイルアプリケーションとの連携であればOpenID Connectを検討するなど、要件に合ったプロトコルを選択します。
  • JITプロビジョニングの活用: 可能な限りJITプロビジョニングを実装し、ユーザー管理の自動化とデータの一貫性確保を目指します。
  • 証明書の管理計画: IdP証明書の有効期限をカレンダーに登録するなどして監視し、余裕を持ったローテーション計画を立てます。
  • デプロビジョニング戦略の確立: JITでカバーされないユーザーの非アクティブ化について、手動プロセスか自動化プロセスかを明確に定義します。
  • 段階的なロールアウト: まずは一部のパイロットユーザーから展開を開始し、問題がないことを確認しながら全社展開へと進めます。
  • ドキュメントの整備: 設定内容、証明書の管理者、緊急時の管理者ログイン手順などを文書化し、関係者間で共有します。

これらのプラクティスに従うことで、安全で安定したSSO環境を構築し、Salesforceプラットフォームの価値を最大限に引き出すことができるでしょう。

コメント