class SAML2::AuthnRequest

def self.initiate(issuer, identity_provider = nil,

Returns:
  • (AuthnRequest) -

Parameters:
  • service_provider (ServiceProvider) --
  • assertion_consumer_service (Endpoint::Indexed) --
  • identity_provider (IdentityProvider) --
  • issuer (NameID) --

Other tags:
    Todo: - go over these params, and use kwargs. Maybe pass Entity instead
def self.initiate(issuer, identity_provider = nil,
    assertion_consumer_service: nil,
    service_provider: nil)
  authn_request = new
  authn_request.issuer = issuer
  authn_request.destination = identity_provider.single_sign_on_services.first.location if identity_provider
  authn_request.name_id_policy = NameID::Policy.new(true, NameID::Format::UNSPECIFIED)
  assertion_consumer_service ||= service_provider.assertion_consumer_services.default if service_provider
  if assertion_consumer_service
    authn_request.protocol_binding = assertion_consumer_service.binding
    authn_request.assertion_consumer_service_url = assertion_consumer_service.location
  end
  authn_request
end

def assertion_consumer_service_index

Returns:
  • (Integer, nil) -
def assertion_consumer_service_index
  if xml && !instance_variable_defined?(:@assertion_consumer_service_index)
    @assertion_consumer_service_index = xml['AssertionConsumerServiceIndex']&.to_i
  end
  @assertion_consumer_service_index
end

def assertion_consumer_service_url

Returns:
  • (String, nil) -
def assertion_consumer_service_url
  if xml && !instance_variable_defined?(:@assertion_consumer_service_url)
    @assertion_consumer_service_url = xml['AssertionConsumerServiceURL']
  end
  @assertion_consumer_service_url
end

def attribute_consuming_service_index

Returns:
  • (Integer, nil) -
def attribute_consuming_service_index
  if xml && !instance_variable_defined?(:@attribute_consuming_service_index)
    @attribute_consuming_service_index = xml['AttributeConsumingServiceIndex']&.to_i
  end
  @attribute_consuming_service_index
end

def build(builder)

(see Base#build)
def build(builder)
  builder['samlp'].AuthnRequest(
      'xmlns:samlp' => Namespaces::SAMLP,
      'xmlns:saml' => Namespaces::SAML
  ) do |authn_request|
    super(authn_request)
    authn_request.parent['AssertionConsumerServiceIndex'] = assertion_consumer_service_index if assertion_consumer_service_index
    authn_request.parent['AssertionConsumerServiceURL'] = assertion_consumer_service_url if assertion_consumer_service_url
    authn_request.parent['AttributeConsumingServiceIndex'] = attribute_consuming_service_index if attribute_consuming_service_index
    authn_request.parent['ForceAuthn'] = force_authn? unless force_authn?.nil?
    authn_request.parent['IsPassive'] = passive? unless passive?.nil?
    authn_request.parent['ProtocolBinding'] = protocol_binding if protocol_binding
    subject.build(authn_request) if subject
    name_id_policy.build(authn_request) if name_id_policy
    requested_authn_context.build(authn_request) if requested_authn_context
  end
end

def force_authn?

Returns:
  • (true, false, nil) -
def force_authn?
  if xml && !instance_variable_defined?(:@force_authn)
    @force_authn = xml['ForceAuthn']&.== 'true'
  end
  @force_authn
end

def name_id_policy

Returns:
  • (NameID::Policy, nil) -
def name_id_policy
  if xml && !instance_variable_defined?(:@name_id_policy)
    @name_id_policy = NameID::Policy.from_xml(xml.at_xpath('samlp:NameIDPolicy', Namespaces::ALL))
  end
  @name_id_policy
end

def passive?

Returns:
  • (true, false, nil) -
def passive?
  if xml && !instance_variable_defined?(:@passive)
    @passive = xml['IsPassive']&.== 'true'
  end
  @passive
end

def protocol_binding

Returns:
  • (String, nil) -
def protocol_binding
  if xml && !instance_variable_defined?(:@protocol_binding)
    @protocol_binding = xml['ProtocolBinding']
  end
  @protocol_binding
end

def resolve(service_provider)

Returns:
  • (Boolean) -

Parameters:
  • service_provider (ServiceProvider) --
def resolve(service_provider)
  # TODO: check signature if present
  if assertion_consumer_service_url
    @assertion_consumer_service = service_provider.assertion_consumer_services.find { |acs| acs.location == assertion_consumer_service_url }
  else
    @assertion_consumer_service  = service_provider.assertion_consumer_services.resolve(assertion_consumer_service_index)
  end
  @attribute_consuming_service = service_provider.attribute_consuming_services.resolve(attribute_consuming_service_index)
  return false unless @assertion_consumer_service
  return false if attribute_consuming_service_index && !@attribute_consuming_service
  true
end

def subject

Returns:
  • (Subject, nil) -
def subject
  if xml && !instance_variable_defined?(:@subject)
    @subject = Subject.from_xml(xml.at_xpath('saml:Subject', Namespaces::ALL))
  end
  @subject
end

def valid_interoperable_profile?

Other tags:
    See: https://saml2int.org/profile/current/#section82 -
def valid_interoperable_profile?
  # It's a subset of Web Browser SSO profile
  return false unless valid_web_browser_sso_profile?
  return false unless assertion_consumer_service_url
  return false if protocol_binding && protocol_binding != Bindings::HTTP_POST::URN
  return false if subject
  true
end

def valid_web_browser_sso_profile?

Other tags:
    See: https://docs.oasis-open.org/security/saml/v2.0/saml-profiles-2.0-os.pdf - section 4.1
def valid_web_browser_sso_profile?
  return false unless issuer
  return false if issuer.format && issuer.format != NameID::Format::ENTITY
  true
end