1

この質問の前に、私は SAML を初めて使用し、その仕組みをほとんど理解していないと言っておきましょう。

セットアップ

devise_saml_authenticatableRails 4 アプリで gem を使用してSSO を実現しています。Rails アプリはサービス プロバイダー (SP) として機能します。セットアップをテストするために、OneLogin 開発者アカウントを作成し、次の属性を使用してSAML テスト コネクタ (属性付き IdP、署名応答付き)をセットアップしました。

構成タブ

SSO タブ

  • 発行者 URL: https://app.onelogin.com/saml/metadata/589819
  • SAML 2.0 エンドポイント (HTTP): https://mysubdomain.onelogin.com/trust/saml2/http-post/sso/589819
  • SLO エンドポイント (HTTP): https://mysubdomain.onelogin.com/trust/saml2/http-redirect/slo/589819
  • SAML 署名アルゴリズム: SHA-1
  • SHA フィンガープリント: 60:9D:18:56:B9:80:D4:25:63:C1:CC:57:6D:B9:06:7C:78:BB:2C:F1
  • X.509 証明書:

    - - -始めるCERTIFICATE----- MIIEFzCCAv+gAwIBAgIUQYRVa1MQpUh0gJaznmXSF/SPqnowDQYJKoZIhvcNAQEF BQAwWDELMAkGA1UEBhMCVVMxETAPBgNVBAoMCEZpcm1QbGF5MRUwEwYDVQQLDAxP bmVMb2dpbiBJZFAxHzAdBgNVBAMMFk9uZUxvZ2luIEFjY291bnQgOTI1MzEwHhcN MTYwOTIxMTU0NzQwWhcNMjEwOTIyMTU0NzQwWjBYMQswCQYDVQQGEwJVUzERMA8G A1UECgwIRmlybVBsYXkxFTATBgNVBAsMDE9uZUxvZ2luIElkUDEfMB0GA1UEAwwW T25lTG9naW4gQWNjb3VudCA5MjUzMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC AQoCggEBALGVgocBj0ciHM3uKlWIcofPhOtzfJw1XpAdNynAvPtbCl7WE5+sLBoQ ZF+oZ7Dl+wRW6DHMJCl9DdKcOaQA6/gr5bwt78IzZ8hWMoKQEPih+E0km6rKLYA8 M52vxtJxGs8Iqx60QvPEePQFMOA+xg73OExfM7W5LnXwNz/Pxgsr3lBif5oCC76j SaTCFroV+TSjfOaYMW/lZrsS79KRIzA9I5XwUBe3bC8bsfQmZXgddCrkQUNSGGaS 7/jtFUlQ94+lAL+l3yoAiNAE6+mt48qqmyLfkKibXvnZ8dwuO272wpY4fEM+vFRy pYrTajqvhY3hYIq8dLw3ominE5VECl8CAwEAAaOB2DCB1TAMBgNVHRMBAf8EAjAA MB0GA1UdDgQWBBSxiuvTPxwOhh2pupID+tuyKCeceTCBlQYDVR0jBIGNMIGKgBSx iuvTPxwOhh2pupID+tuyKCeceaFcpFowWDELMAkGA1UEBhMCVVMxETAPBgNVBAoM CEZpcm1QbGF5MRUwEwYDVQQLDAxPbmVMb2dpbiBJZFAxHzAdBgNVBAMMFk9uZUxv Z2luIEFjY291bnQgOTI1MzGCFEGEVWtTEKVIdICWs55l0hf0j6p6MA4GA1UdDwEB /wQEAwIHgDANBgkqhkiG9w0BAQUFAAOCAQEAYBe+5d3zpLZ7fcf3l3rXYeIxcpN+ 9D2YZCbxsrBhY2Am4YE9nN+RaJXeDqeRBNtpayCZVxfHnXexRo1n7wxwTmosiydi 9yE7SY2xZf+3feQreF25atnn4tzVhxYONaX1njZMIt/TNa7A9aeDfHSD+vwSuYYB hGxKT6HOkEAEBiXCZ/FcVNiB0D8bRwQhiJ3BTzXDfqHrmq8QYdn3Ejlqo62vMl6W XeMXUoyv6cUc64Ap6E+XtEQI1E8YB5R8GtTs3Y1Oa2dD6yWyCyVJ20+Hi7IWAqXC EfqstqXB7FoQ2rAt39cepnu1SOarvEYDMwYIaVNF3hoyodBybJJsAwAnCQ== -----END CERTIFICATE-----証明書 - - -証明書 - - -証明書 - - -証明書 - - -

devise.rbの場合、次の構成があります。

config.saml_create_user = false
config.saml_update_user = true
config.saml_default_user_key = :email
config.saml_session_index_key = :session_index
config.saml_use_subject = true
config.idp_settings_adapter = IdPSettingsAdapter
config.idp_entity_id_reader = DeviseSamlAuthenticatable::DefaultIdpEntityIdReader

これが私のものIdPSettingsAdapterです:

class IdPSettingsAdapter
    def self.settings(idp_entity_id)
        company = Company.find_by(idp_entity_id: idp_entity_id)

        if company.present?
            {
                assertion_consumer_service_url: company.assertion_consumer_service_url,
                assertion_consumer_service_binding: company.assertion_consumer_service_binding,
                name_identifier_format: company.name_identifier_format,
                issuer: company.issuer,
                idp_entity_id: company.idp_entity_id,
                authn_context: company.authn_context,
                idp_slo_target_url: company.idp_slo_target_url,
                idp_sso_target_url: company.idp_sso_target_url,
                idp_cert_fingerprint: company.idp_cert_fingerprint
            }
        else
            {}
        end
    end
end

私のユーザーモデルはContactbelongs_toCompanyであり、SSO 設定はCompanyモデルに保存されていることに注意してください。

ここに私のsmlルートがあります:

devise_for :contacts, skip: :saml_authenticatable, controllers: {
    registrations: "registrations",
    sessions: "sessions",
    passwords: "passwords",
    confirmations: "confirmations"
}
devise_scope :contact do
    get '/sign_in' => 'sessions#new'
    get '/sign_out' => 'sessions#destroy'

    # SSO Routes
    get 'saml/sign_in' => 'saml_sessions#new', as: :new_user_sso_session
    post 'saml/auth' => 'saml_sessions#create', as: :user_sso_session
    get 'saml/sign_out' => 'saml_sessions#destroy', as: :destroy_user_sso_session
    get 'saml/metadata' => 'saml_sessions#metadata', as: :metadata_user_sso_session
    match 'saml/idp_sign_out' => 'saml_sessions#idp_sign_out', via: [:get, :post]
end

最後に、これが私のものSamlSessionsControllerです:

require "ruby-saml"

class SamlSessionsController < SessionsController
    include DeviseSamlAuthenticatable::SamlConfig
    skip_before_filter :verify_authenticity_token, raise: false
    before_action :authorize_viewer, except: [:metadata]
    protect_from_forgery with: :null_session, except: :create

    def new
        idp_entity_id = Company.friendly.find(@_request.env['HTTP_HOST'].split('.')[0]).idp_entity_id
        request = OneLogin::RubySaml::Authrequest.new
        action = request.create(saml_config(idp_entity_id))
        redirect_to action
    end

    def metadata
        idp_entity_id = Company.friendly.find(@_request.env['HTTP_HOST'].split('.')[0]).idp_entity_id
        meta = OneLogin::RubySaml::Metadata.new
        render :xml => meta.generate(saml_config(idp_entity_id)), content_type: 'application/samlmetadata+xml'
    end

    def create
        @idp_entity_id = Company.friendly.find(@_request.env['HTTP_HOST'].split('.')[0]).idp_entity_id
        response = OneLogin::RubySaml::Response.new(params[:SAMLResponse], settings: saml_config(@idp_entity_id))

        if !response.is_valid?
            puts "SAML FAILED WITH ERROR: "
            puts response.errors
        end
        super
    end

    def idp_sign_out
        company = Company.friendly.find(request.subdomain.downcase)
        idp_entity_id = Company.friendly.find(@_request.env['HTTP_HOST'].split('.')[0]).idp_entity_id

        if params[:SAMLRequest] && Devise.saml_session_index_key
            saml_config = saml_config(idp_entity_id)
            logout_request = OneLogin::RubySaml::SloLogoutrequest.new(params[:SAMLRequest], settings: saml_config(idp_entity_id))
            resource_class.reset_session_key_for(logout_request.name_id)

            # binding.pry
            sign_out current_contact if contact_signed_in?
            redirect_to company.after_slo_url.present? ? company.after_slo_url : 'https://' + company.issuer
            # redirect_to generate_idp_logout_response(saml_config(idp_entity_id), logout_request.id)
        elsif params[:SAMLResponse]
            #Currently Devise handles the session invalidation when the request is made.
            #To support a true SP initiated logout response, the request ID would have to be tracked and session invalidated
            #based on that.
            if Devise.saml_sign_out_success_url
                redirect_to Devise.saml_sign_out_success_url
            else
                redirect_to action: :new
            end
        else
            head :invalid_request
        end
    end

    protected

    # Override devise to send user to IdP logout for SLO
    def after_sign_out_path_for(_)
        request = OneLogin::RubySaml::Logoutrequest.new
        request.create(saml_config)
    end

    def generate_idp_logout_response(saml_config, logout_request_id)
        OneLogin::RubySaml::SloLogoutresponse.new.create(saml_config, logout_request_id, nil)
    end
end

問題

OneLogin アダプターからCompanyモデルにマップ設定を手動で保存すると (スクリーンショットを参照)、OneLogin を ID プロバイダー (IdP) として使用してアプリのユーザーとして認証できます。ただし、アプリのセットアップを表す XML メタデータをクライアントに提供する必要があります。にアクセスすると/saml/metadata.xml、次の構成が表示されますが、クライアントによると、これは正しくありません。クライアントは、問題が何であるかについてそれ以上の詳細を提供しませんでした. 問題があれば、彼らは PingFederate を使用しています。

<?xml version='1.0' encoding='UTF-8'?>
<md:EntityDescriptor ID='_a3581975-b73d-4784-a106-bafd61e15f87' xmlns:md='urn:oasis:names:tc:SAML:2.0:metadata'>
    <md:SPSSODescriptor AuthnRequestsSigned='false' WantAssertionsSigned='false' protocolSupportEnumeration='urn:oasis:names:tc:SAML:2.0:protocol'>
        <md:NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:transient</md:NameIDFormat>
        <md:AssertionConsumerService Binding='urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST' Location='https://mysubdomain.myapp.local:3000/saml/auth' index='0' isDefault='true'/>
    </md:SPSSODescriptor>
</md:EntityDescriptor>

ここに画像の説明を入力

私の質問は、ここで何が間違っているのか、どうすれば修正できるのかということです。私が言ったように、私は SAML が内部でどのように機能するかをほとんど理解していません。

4

1 に答える 1

1

そのメタデータ XML には EntityID が定義されていません。検証ツールで XML を検証しようとすると、次のようになります。

行: 2 | 列: 0 --> 要素 '{urn:oasis:names:tc:SAML:2.0:metadata}EntityDescriptor': 属性 'entityID' が必要ですが、欠落しています。

ruby-saml コードを確認すると、settings.issuerが定義されている場合、EntityID がメタデータ XML に追加されます。そのデータが提供されているかどうかを確認できますか? IdPSettingsAdapter クラスで表示される company.issuer の値が空の可能性があります。

于 2016-11-08T00:11:14.967 に答える