generate saml authnrequests with saml2 gem

closes CNVS-36682

note that the old way of doing it is still there, controlled by a hidden
account level setting

test plan:
 * smoke test a SAML login

Change-Id: I24c8c6ee472b90e274ec93d09cc6f58d03ed77f5
Reviewed-on: https://gerrit.instructure.com/130136
Reviewed-by: Rob Orton <rob@instructure.com>
QA-Review: Jeremy Putnam <jeremyp@instructure.com>
Tested-by: Jenkins
Product-Review: Cody Cutrer <cody@instructure.com>
This commit is contained in:
Cody Cutrer 2017-10-18 10:52:09 -06:00
parent 5f54decbce
commit d2ea1fb2a9
3 changed files with 48 additions and 20 deletions

View File

@ -97,7 +97,7 @@ gem 'rotp', '3.3.0', require: false
gem 'net-ldap', '0.16.0', require: false
gem 'ruby-duration', '3.2.3', require: false
gem 'ruby-saml-mod', '0.3.7'
gem 'saml2', '1.1.3', require: false
gem 'saml2', '1.1.5', require: false
gem 'nokogiri-xmlsec-me-harder', '0.9.3pre', require: false, github: 'instructure/nokogiri-xmlsec-me-harder', ref: '57d071040cc4649db9f158e09bbcea028271a4a6'
gem 'rubycas-client', '2.3.9', require: false
gem 'rubyzip', '1.2.0', require: 'zip'

View File

@ -26,7 +26,9 @@ class Login::SamlController < ApplicationController
before_action :fix_ms_office_redirects, only: :new
def new
auth_redirect(aac)
increment_saml_stat("login_attempt")
redirect_to delegated_auth_redirect_uri(aac.generate_authn_request_redirect(host: request.host_with_port,
parent_registration: session[:parent_registration]))
end
def create
@ -324,7 +326,10 @@ class Login::SamlController < ApplicationController
def observee_validation
auth_redirect(@domain_root_account.parent_registration_aac)
increment_saml_stat("login_attempt")
redirect_to delegated_auth_redirect_uri(
@domain_root_account.parent_registration_aac.generate_authn_request_redirect(host: request.host_with_port,
parent_registration: session[:parent_registration]))
end
protected
@ -340,21 +345,6 @@ class Login::SamlController < ApplicationController
CanvasStatsd::Statsd.increment("saml.#{CanvasStatsd::Statsd.escape(request.host)}.#{key}")
end
def auth_redirect(aac)
increment_saml_stat("login_attempt")
settings = aac.saml_settings(request.host_with_port)
request = Onelogin::Saml::AuthRequest.new(settings)
forward_url = request.generate_request
if aac.debugging? && !aac.debug_get(:request_id)
aac.debug_set(:request_id, request.id)
aac.debug_set(:to_idp_url, forward_url)
aac.debug_set(:to_idp_xml, request.request_xml)
aac.debug_set(:debugging, "Forwarding user to IdP for authentication")
end
forward_url << '&ForceAuthn=true' if session[:parent_registration]
redirect_to delegated_auth_redirect_uri(forward_url)
end
def complete_observee_addition(registration_data)
observee_unique_id = registration_data[:observee][:unique_id]
observee = @domain_root_account.pseudonyms.by_unique_id(observee_unique_id).first.user

View File

@ -196,9 +196,11 @@ class AccountAuthorizationConfig::SAML < AccountAuthorizationConfig::Delegated
entity.entity_id = idp_entity_id
idp = SAML2::IdentityProvider.new
idp.single_sign_on_services << SAML2::Endpoint.new(log_in_url,
SAML2::Bindings::HTTPRedirect::URN)
if log_out_url.present?
idp.single_logout_services << SAML2::Endpoint.new(log_out_url,
SAML2::Endpoint::Bindings::HTTP_REDIRECT)
SAML2::Bindings::HTTPRedirect::URN)
end
entity.roles << idp
entity
@ -218,7 +220,7 @@ class AccountAuthorizationConfig::SAML < AccountAuthorizationConfig::Delegated
sp = SAML2::ServiceProvider.new
sp.single_logout_services << SAML2::Endpoint.new("#{HostUrl.protocol}://#{hosts.first}/login/saml/logout",
SAML2::Endpoint::Bindings::HTTP_REDIRECT)
SAML2::Bindings::HTTPRedirect::URN)
hosts.each_with_index do |host, i|
sp.assertion_consumer_services << SAML2::Endpoint::Indexed.new("#{HostUrl.protocol}://#{host}/login/saml",
@ -240,6 +242,42 @@ class AccountAuthorizationConfig::SAML < AccountAuthorizationConfig::Delegated
entity
end
def generate_authn_request_redirect(host: nil, parent_registration: false)
if account.settings[:use_legacy_saml_authn_request]
settings = saml_settings(host)
request = Onelogin::Saml::AuthRequest.new(settings)
forward_url = request.generate_request
if debugging? && !debug_get(:request_id)
debug_set(:request_id, request.id)
debug_set(:to_idp_url, forward_url)
debug_set(:to_idp_xml, request.request_xml)
debug_set(:debugging, "Forwarding user to IdP for authentication")
end
forward_url << '&ForceAuthn=true' if parent_registration
else
sp_metadata = self.class.sp_metadata_for_account(account, host).service_providers.first
authn_request = SAML2::AuthnRequest.initiate(SAML2::NameID.new(entity_id),
idp_metadata.identity_providers.first,
service_provider: sp_metadata)
authn_request.name_id_policy.format = identifier_format if identifier_format.present?
if requested_authn_context.present?
authn_request.requested_authn_context = RequestedAuthnContext.new
authn_request.requested_authn_context.class_ref = requested_authn_context
authn_request.requested_authn_context.comparison = :exact
end
authn_request.force_authn = true if parent_registration
forward_url = SAML2::Bindings::HTTPRedirect.encode(authn_request)
if debugging? && !debug_get(:request_id)
debug_set(:request_id, authn_request.id)
debug_set(:to_idp_url, forward_url)
debug_set(:to_idp_xml, authn_request.to_s)
debug_set(:debugging, "Forwarding user to IdP for authentication")
end
end
forward_url
end
def self.sp_metadata_for_account(account, current_host = nil)
sp_metadata(saml_default_entity_id_for_account(account),HostUrl.context_hosts(account, current_host))
end