Skip to content

Instantly share code, notes, and snippets.

@shimoju

shimoju/saml.rb Secret

Last active June 7, 2021 15:04
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save shimoju/88de57a32674af583d3238e2763c19bb to your computer and use it in GitHub Desktop.
Save shimoju/88de57a32674af583d3238e2763c19bb to your computer and use it in GitHub Desktop.
module Saml
module_function
def authenticated?(session)
session[:saml_authenticated_at]&.between?(Settings.saml.expires_in.seconds.ago, Time.zone.now) || false
end
def auth_request_url(relay_state: nil)
OneLogin::RubySaml::Authrequest.new.create(settings, RelayState: relay_state)
end
def metadata_xml
OneLogin::RubySaml::Metadata.new.generate(settings)
end
def decode_response(message)
OneLogin::RubySaml::Response.new(message, settings: settings)
end
def decode_logout_request(message)
OneLogin::RubySaml::SloLogoutrequest.new(message)
end
def logout_response_url(logout_request, relay_state: nil)
OneLogin::RubySaml::SloLogoutresponse.new.create(
settings,
logout_request.id,
nil,
RelayState: relay_state
)
end
def settings
OneLogin::RubySaml::Settings.new.tap do |settings|
settings.assertion_consumer_service_url = Settings.saml.assertion_consumer_service_url
settings.sp_entity_id = Settings.saml.sp_entity_id
settings.idp_entity_id = Settings.saml.idp_entity_id
settings.idp_sso_target_url = Settings.saml.idp_sso_target_url
settings.idp_slo_target_url = Settings.saml.idp_slo_target_url
settings.name_identifier_format = 'urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress'
settings.idp_cert = File.read(Rails.root.join('config', 'onelogin.pem'))
end
end
end
class Admin::SamlAuthenticationsController < Admin::ApplicationController
# SAMLで検証されるのでCSRF対策は不要
protect_from_forgery except: :create
# sp_entity_id(metadata)
def show
render xml: Saml.metadata_xml
end
# このURLにアクセスするとIdPに飛ぶ(SP-initiated SSO)
def new
# RelayStateに入れた情報はそのままIdPから返ってくる
# これを使って認証後アクセスしようとしていたURLへリダイレクトする
# danger_next_pathではセッションやクエリパラメータに入れた「ログイン後リダイレクトしたいURL」を統一的に扱っている
relay_state =
if danger_next_path.present?
{ next: danger_next_path }.to_json
end
redirect_to Saml.auth_request_url(relay_state: relay_state)
end
# Assertion Consumer Service URL
def create
response = Saml.decode_response(params[:SAMLResponse])
unless response.is_valid?
return redirect_to root_url, alert: 'ログインに失敗しました。不正なSAMLレスポンスです'
end
if user = User.where(foobar).find_by(email: response.name_id)
log_in user
session[:saml_authenticated_at] = Time.zone.now
# RelayStateがあればアクセスしようとしていたパスを取り出しそこにリダイレクトする
# next_urlではオープンリダイレクト対策を施す
redirect_to next_url(fallback_location: admin_root_url), notice: "#{user.name}でログインしました"
else
redirect_to root_url, alert: 'ログインに失敗しました'
end
end
# Single Logout URL
def destroy
logout_request = Saml.decode_logout_request(params[:saml_request])
unless logout_request.is_valid?
return redirect_to root_url, alert: 'ログアウトに失敗しました。不正なSAMLリクエストです'
end
log_out
redirect_to Saml.logout_response_url(logout_request, relay_state: params[:relay_state])
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment