sso_login_box_for_ntu/app/controllers/sso_login_box_controller.rb

126 lines
5.9 KiB
Ruby

class SsoLoginBoxController < SessionsController
require 'openssl'
require 'onelogin/ruby-saml'
OpenSSL::SSL::VERIFY_PEER = OpenSSL::SSL::VERIFY_NONE
def sso_auth_page
session[:referer_url] = params[:referer_url]
# puts ["session", session, session.to_hash]
request = OneLogin::RubySaml::Authrequest.new
redirect_to(request.create(saml_settings))
end
def sso_sign_in
puts ["SSO sign in"]
puts "------------------------------"
response = OneLogin::RubySaml::Response.new(params[:SAMLResponse], {:settings => saml_settings, :allowed_clock_drift=> "60"})
# puts response.inspect
# response = OneLogin::RubySaml::Response.new(params[:SAMLResponse], {skip_authnstatement: true}) # skips AuthnStatement
# response = OneLogin::RubySaml::Response.new(params[:SAMLResponse], {skip_conditions: true}) # skips conditions
# response = OneLogin::RubySaml::Response.new(params[:SAMLResponse], {skip_subject_confirmation: true}) # skips subject confirmation
# response = OneLogin::RubySaml::Response.new(params[:SAMLResponse], {skip_recipient_check: true}) # doesn't skip subject confirmation, but skips the recipient check which is a sub check of the subject_confirmation check
# response = OneLogin::RubySaml::Response.new(params[:SAMLResponse], {skip_audience: true}) # skips audience check
# We validate the SAML Response and check if the user already exists in the system
if response.is_valid?
attributes = response.attributes
# puts ["attributes", attributes.inspect]
if true#["f", "s"].include?(attributes["AccountTypeCode"])
email = attributes["http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress"]
member_name = attributes["ChineseName"]
sid = attributes["SEQ"]
matched_member = sid.present? ? MemberProfile.where(:sid=>sid).first : nil
user = nil
if matched_member
user = matched_member.user
else
matched_member = MemberProfile.where(:email=>email).first
if matched_member
user = matched_member.user
else
user = member_name.present? ? User.where("member_name.zh_tw"=> member_name).first : nil
end
end
if !user.nil?
puts "Login #{user.user_name} success by sso!"
session[:sso_token] = user.id
session[:user_id] = user.id
session[:login_referer] = nil
if params[:referer_url].present?
redirect_to URI.parse(params[:referer_url]).path
else
redirect_to admin_dashboards_path
end
else
@login_referer = session[:referer_url]
flash.now.alert = I18n.t("sso_login_box_for_ntu.user_not_in_database",:sid=>sid,:name=>member_name,:email=>email).gsub("\n","<br>").html_safe
render "new"
end
else
@login_referer = session[:referer_url]
flash.now.alert = I18n.t("sso_login_box_for_ntu.not_staff")
render "new"
end
else
puts ["errors", response.instance_variable_get(:@errors)]
@login_referer = session[:referer_url]
flash.now.alert = I18n.t("sso_login_box_for_ntu.sso_authorized_failure")
render "new"
end
end
def delete_session
reset_session
end
# Create a SP initiated SLO
def sp_logout_request
# LogoutRequest accepts plain browser requests w/o paramters
settings = saml_settings
if settings.idp_slo_service_url.nil?
delete_session
else
logout_request = OneLogin::RubySaml::Logoutrequest.new
if settings.name_identifier_value.nil?
settings.name_identifier_value = session[:user_id]
end
# Ensure user is logged out before redirect to IdP, in case anything goes wrong during single logout process (as recommended by saml2int [SDP-SP34])
logged_user = session[:user_id]
delete_session
# Save the transaction_id to compare it with the response we get back
session[:transaction_id] = logout_request.uuid
session[:logged_out_user] = logged_user
relayState = "https://#{request.host}"
redirect_to(logout_request.create(settings, :RelayState => relayState))
end
end
private
def saml_settings
settings = OneLogin::RubySaml::Settings.new
request_host = request.host
settings.assertion_consumer_service_url = "https://#{request_host}/ntu_sso/response"
settings.issuer = request_host
settings.idp_sso_target_url = "https://adfs.ntu.edu.tw/adfs/ls/"
# settings.idp_sso_target_binding = "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" # or :post, :redirect
settings.idp_slo_target_url = "https://adfs.ntu.edu.tw/adfs/ls/clearall.aspx?url=https://#{request_host}"
# settings.idp_slo_service_binding = "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" # or :post, :redirect
settings.idp_cert_fingerprint = (File.read('adfs_fingerprint.txt') rescue '') #"0A:27:FC:D5:CE:DC:D8:44:CC:A9:58:8A:42:D1:F4:DF:38:2E:4A:C3"
settings.idp_cert_fingerprint_algorithm = "http://www.w3.org/2000/09/xmldsig#sha1"
# settings.security[:signature_method] = XMLSecurity::Document::SHA256
# settings.name_identifier_format = "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress"
# # Optional for most SAML IdPs
# settings.authn_context = "urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport"
# # or as an array
# settings.authn_context = [
# "urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport",
# "urn:oasis:names:tc:SAML:2.0:ac:classes:Password"
# ]
# Optional bindings (defaults to Redirect for logout POST for ACS)
settings.single_logout_service_binding = "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" # or :post, :redirect
settings.assertion_consumer_service_binding = "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" # or :post, :redirect
settings
end
end