rsaml 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/LICENSE +0 -0
- data/README +13 -0
- data/Rakefile +136 -0
- data/lib/rsaml.rb +57 -0
- data/lib/rsaml/action.rb +57 -0
- data/lib/rsaml/action_namespace.rb +63 -0
- data/lib/rsaml/advice.rb +34 -0
- data/lib/rsaml/assertion.rb +192 -0
- data/lib/rsaml/attribute.rb +76 -0
- data/lib/rsaml/audience.rb +19 -0
- data/lib/rsaml/authentication_context.rb +34 -0
- data/lib/rsaml/authn_context/README +1 -0
- data/lib/rsaml/authn_context/authentication_context_declaration.rb +42 -0
- data/lib/rsaml/authn_context/identification.rb +10 -0
- data/lib/rsaml/authn_context/physical_verification.rb +24 -0
- data/lib/rsaml/condition.rb +13 -0
- data/lib/rsaml/conditions.rb +107 -0
- data/lib/rsaml/encrypted.rb +12 -0
- data/lib/rsaml/errors.rb +16 -0
- data/lib/rsaml/evidence.rb +21 -0
- data/lib/rsaml/ext/string.rb +5 -0
- data/lib/rsaml/identifier.rb +9 -0
- data/lib/rsaml/identifier/base.rb +23 -0
- data/lib/rsaml/identifier/issuer.rb +28 -0
- data/lib/rsaml/identifier/name.rb +55 -0
- data/lib/rsaml/parser.rb +23 -0
- data/lib/rsaml/protocol.rb +21 -0
- data/lib/rsaml/protocol/artifact_resolve.rb +14 -0
- data/lib/rsaml/protocol/assertion_id_request.rb +18 -0
- data/lib/rsaml/protocol/authn_request.rb +91 -0
- data/lib/rsaml/protocol/idp_entry.rb +18 -0
- data/lib/rsaml/protocol/idp_list.rb +28 -0
- data/lib/rsaml/protocol/message.rb +65 -0
- data/lib/rsaml/protocol/name_id_policy.rb +31 -0
- data/lib/rsaml/protocol/query.rb +12 -0
- data/lib/rsaml/protocol/query/attribute_query.rb +56 -0
- data/lib/rsaml/protocol/query/authn_query.rb +30 -0
- data/lib/rsaml/protocol/query/authz_decision_query.rb +40 -0
- data/lib/rsaml/protocol/query/subject_query.rb +22 -0
- data/lib/rsaml/protocol/request.rb +27 -0
- data/lib/rsaml/protocol/requested_authn_context.rb +34 -0
- data/lib/rsaml/protocol/response.rb +56 -0
- data/lib/rsaml/protocol/scoping.rb +33 -0
- data/lib/rsaml/protocol/status.rb +38 -0
- data/lib/rsaml/protocol/status_code.rb +84 -0
- data/lib/rsaml/proxy_restriction.rb +30 -0
- data/lib/rsaml/statement.rb +10 -0
- data/lib/rsaml/statement/attribute_statement.rb +27 -0
- data/lib/rsaml/statement/authentication_statement.rb +57 -0
- data/lib/rsaml/statement/authorization_decision_statement.rb +53 -0
- data/lib/rsaml/statement/base.rb +9 -0
- data/lib/rsaml/subject.rb +37 -0
- data/lib/rsaml/subject_confirmation.rb +35 -0
- data/lib/rsaml/subject_confirmation_data.rb +55 -0
- data/lib/rsaml/subject_locality.rb +27 -0
- data/lib/rsaml/validatable.rb +21 -0
- data/lib/rsaml/version.rb +9 -0
- data/lib/xml_enc.rb +3 -0
- data/lib/xml_sig.rb +11 -0
- data/lib/xml_sig/canonicalization_method.rb +43 -0
- data/lib/xml_sig/key_info.rb +55 -0
- data/lib/xml_sig/reference.rb +57 -0
- data/lib/xml_sig/signature.rb +29 -0
- data/lib/xml_sig/signature_method.rb +20 -0
- data/lib/xml_sig/signed_info.rb +27 -0
- data/lib/xml_sig/transform.rb +37 -0
- data/test/action_namespace_test.rb +93 -0
- data/test/action_test.rb +51 -0
- data/test/advice_test.rb +25 -0
- data/test/assertion_test.rb +192 -0
- data/test/attribute_test.rb +60 -0
- data/test/authentication_context_test.rb +26 -0
- data/test/conditions_test.rb +84 -0
- data/test/evidence_test.rb +33 -0
- data/test/identifier_test.rb +22 -0
- data/test/issuer_test.rb +33 -0
- data/test/name_test.rb +33 -0
- data/test/parser_test.rb +32 -0
- data/test/protocol/assertion_id_request_test.rb +19 -0
- data/test/protocol/attribute_query_test.rb +30 -0
- data/test/protocol/authn_query_test.rb +20 -0
- data/test/protocol/authn_request_test.rb +56 -0
- data/test/protocol/authz_decision_query_test.rb +31 -0
- data/test/protocol/idp_list_test.rb +15 -0
- data/test/protocol/request_test.rb +66 -0
- data/test/protocol/response_test.rb +68 -0
- data/test/protocol/scoping_test.rb +20 -0
- data/test/protocol/status_code_test.rb +34 -0
- data/test/protocol/status_test.rb +16 -0
- data/test/proxy_restriction_test.rb +20 -0
- data/test/rsaml_test.rb +12 -0
- data/test/statement_test.rb +101 -0
- data/test/subject_locality_test.rb +27 -0
- data/test/subject_test.rb +44 -0
- data/test/test_helper.rb +16 -0
- data/test/xml_sig/canonicalization_test.rb +19 -0
- metadata +187 -0
@@ -0,0 +1,55 @@
|
|
1
|
+
module RSAML #:nodoc:
|
2
|
+
module Identifier #:nodoc:
|
3
|
+
# A Name identifier.
|
4
|
+
class Name < Base
|
5
|
+
# The following identifiers MAY be used to refer to the classification of the attribute name
|
6
|
+
# for purposes of interpreting the name.
|
7
|
+
def self.formats
|
8
|
+
{
|
9
|
+
:unspecified => 'urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified',
|
10
|
+
:email_address => 'urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress',
|
11
|
+
:x509_subject_name => 'urn:oasis:names:tc:SAML:1.1:nameid-format:X509SubjectName',
|
12
|
+
:windows_domain_qualified_name => 'urn:oasis:names:tc:SAML:1.1:nameid-format:WindowsDomainQualifiedName',
|
13
|
+
:kerberos => 'urn:oasis:names:tc:SAML:2.0:nameid-format:kerberos',
|
14
|
+
:entity => 'urn:oasis:names:tc:SAML:2.0:nameid-format:entity',
|
15
|
+
:persistent => 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent',
|
16
|
+
:transient => 'urn:oasis:names:tc:SAML:2.0:nameid-format:transient'
|
17
|
+
}
|
18
|
+
end
|
19
|
+
|
20
|
+
# A URI reference representing the classification of string-based identifier information.
|
21
|
+
attr_accessor :format
|
22
|
+
|
23
|
+
# A name identifier established by a service provider or affiliation of providers for the entity, if
|
24
|
+
# different from the primary name identifier given
|
25
|
+
attr_accessor :sp_provided_id
|
26
|
+
|
27
|
+
# The value of the identifier
|
28
|
+
attr_accessor :value
|
29
|
+
|
30
|
+
# Initialize the identifier with the given value
|
31
|
+
def initialize(value)
|
32
|
+
@value = value
|
33
|
+
end
|
34
|
+
|
35
|
+
# The format of the name.
|
36
|
+
def format
|
37
|
+
@format ||= Name.formats[:unspecified]
|
38
|
+
end
|
39
|
+
|
40
|
+
# Construct an XML fragment representing the name
|
41
|
+
def to_xml(xml=Builder::XmlMarkup.new)
|
42
|
+
attributes = {'Format' => format}
|
43
|
+
attributes['NameQualifier'] = name_qualifier unless name_qualifier.nil?
|
44
|
+
attributes['SPNameQualifier'] = sp_name_qualifier unless sp_name_qualifier.nil?
|
45
|
+
attributes['SPProvidedID'] = sp_provided_id unless sp_provided_id.nil?
|
46
|
+
xml.tag!('saml:NameID', value, attributes)
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.from_xml(element)
|
50
|
+
Name.new(element.text)
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
data/lib/rsaml/parser.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
module RSAML #:nodoc:
|
2
|
+
class Parser
|
3
|
+
# Parse the given SAML message and return a Ruby object structure representing
|
4
|
+
# the message. This may include protocol and core classes.
|
5
|
+
def parse(xml)
|
6
|
+
messages = []
|
7
|
+
xml = REXML::Document.new(xml) if xml.is_a?(String)
|
8
|
+
|
9
|
+
if attribute_query_elements = xml.get_elements('samlp:AttributeQuery')
|
10
|
+
attribute_query_elements.each do |attribute_query_element|
|
11
|
+
messages << Protocol::Query::AttributeQuery.from_xml(attribute_query_element)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
case messages.length
|
16
|
+
when 1: messages.first
|
17
|
+
when 0: nil
|
18
|
+
else
|
19
|
+
messages
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module RSAML #:nodoc:
|
2
|
+
# The protocol module contains request and response classes for the SAML protocol implementation
|
3
|
+
module Protocol
|
4
|
+
end
|
5
|
+
end
|
6
|
+
|
7
|
+
require 'rsaml/protocol/message'
|
8
|
+
require 'rsaml/protocol/status_code'
|
9
|
+
require 'rsaml/protocol/status'
|
10
|
+
require 'rsaml/protocol/request'
|
11
|
+
require 'rsaml/protocol/response'
|
12
|
+
|
13
|
+
require 'rsaml/protocol/name_id_policy'
|
14
|
+
require 'rsaml/protocol/scoping'
|
15
|
+
require 'rsaml/protocol/idp_list'
|
16
|
+
require 'rsaml/protocol/idp_entry'
|
17
|
+
|
18
|
+
require 'rsaml/protocol/assertion_id_request'
|
19
|
+
require 'rsaml/protocol/authn_request'
|
20
|
+
|
21
|
+
require 'rsaml/protocol/query'
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module RSAML #:nodoc:
|
2
|
+
module Protocol #:nodoc:
|
3
|
+
# The ArtifactResolve message is used to request that a SAML protocol message be returned in an
|
4
|
+
# <ArtifactResponse> message by specifying an artifact that represents the SAML protocol message.
|
5
|
+
# The original transmission of the artifact is governed by the specific protocol binding that is
|
6
|
+
# being used; see [SAMLBind] for more information on the use of artifacts in bindings.
|
7
|
+
#
|
8
|
+
# The <ArtifactResolve> message SHOULD be signed or otherwise authenticated and integrity
|
9
|
+
# protected by the protocol binding used to deliver the message.
|
10
|
+
class ArtifactResolve
|
11
|
+
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module RSAML #:nodoc:
|
2
|
+
module Protocol #:nodoc:
|
3
|
+
# Request to return assertions with the given ids
|
4
|
+
class AssertionIDRequest
|
5
|
+
# Specify each assertion to return.
|
6
|
+
def assertion_id_refs
|
7
|
+
@assertion_id_refs ||= []
|
8
|
+
end
|
9
|
+
|
10
|
+
# Construct an XML fragment representing the assertion id request
|
11
|
+
def to_xml(xml=Builder::XmlMarkup.new)
|
12
|
+
xml.tag!('samlp:AssertionIDRequest') {
|
13
|
+
assertion_id_refs.each { |assertion_id_ref| xml << assertion_id_ref.to_xml }
|
14
|
+
}
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
module RSAML #:nodoc:
|
2
|
+
module Protocol #:nodoc:
|
3
|
+
# To request that an identity provider issue an assertion with an authentication statement, a presenter
|
4
|
+
# authenticates to that identity provider (or relies on an existing security context) and sends it an
|
5
|
+
# <AuthnRequest> message that describes the properties that the resulting assertion needs to have to
|
6
|
+
# satisfy its purpose. Among these properties may be information that relates to the content of the assertion
|
7
|
+
# and/or information that relates to how the resulting <Response> message should be delivered to the
|
8
|
+
# requester. The process of authentication of the presenter may take place before, during, or after the initial
|
9
|
+
# delivery of the <AuthnRequest> message.
|
10
|
+
#
|
11
|
+
# The requester might not be the same as the presenter of the request if, for example, the requester is a
|
12
|
+
# relying party that intends to use the resulting assertion to authenticate or authorize the requested subject
|
13
|
+
# so that the relying party can decide whether to provide a service.
|
14
|
+
class AuthnRequest < Request
|
15
|
+
# Specifies the requested subject of the resulting assertion(s).
|
16
|
+
attr_accessor :subject
|
17
|
+
|
18
|
+
# Specifies constraints on the name identifier to be used to represent the requested subject. If omitted,
|
19
|
+
# then any type of identifier supported by the identity provider for the requested subject can be used,
|
20
|
+
# constrained by any relevant deployment-specific policies, with respect to privacy, for example.
|
21
|
+
attr_accessor :name_id_policy
|
22
|
+
|
23
|
+
# Specifies the SAML conditions the requester expects to limit the validity and/or use of the resulting
|
24
|
+
# assertion(s). The responder MAY modify or supplement this set as it deems necessary. The
|
25
|
+
# information in this element is used as input to the process of constructing the assertion, rather than as
|
26
|
+
# conditions on the use of the request itself.
|
27
|
+
attr_accessor :conditions
|
28
|
+
|
29
|
+
# Specifies the requirements, if any, that the requester places on the authentication context that applies
|
30
|
+
# to the responding provider's authentication of the presenter.
|
31
|
+
attr_accessor :requested_authn_context
|
32
|
+
|
33
|
+
# Specifies a set of identity providers trusted by the requester to authenticate the presenter, as well as
|
34
|
+
# limitations and context related to proxying of the <Au message to subsequent identity providers by the
|
35
|
+
# responder.
|
36
|
+
attr_accessor :scoping
|
37
|
+
|
38
|
+
# A Boolean value. If "true", the identity provider MUST authenticate the presenter directly rather than
|
39
|
+
# rely on a previous security context. If a value is not provided, the default is "false". However, if both
|
40
|
+
# ForceAuthn and IsPassive are "true", the identity provider MUST NOT freshly authenticate the
|
41
|
+
# presenter unless the constraints of IsPassive can be met.
|
42
|
+
attr_accessor :force_authn
|
43
|
+
|
44
|
+
# A Boolean value. If "true", the identity provider and the user agent itself MUST NOT visibly take control
|
45
|
+
# of the user interface from the requester and interact with the presenter in a noticeable fashion. If a
|
46
|
+
# value is not provided, the default is "false".
|
47
|
+
attr_accessor :is_passive
|
48
|
+
|
49
|
+
attr_accessor :assertion_consumer_service_index
|
50
|
+
|
51
|
+
attr_accessor :assertion_consumer_service_url
|
52
|
+
|
53
|
+
# A URI reference that identifies a SAML protocol binding to be used when returning the response message.
|
54
|
+
attr_accessor :protocol_binding
|
55
|
+
|
56
|
+
# Indirectly identifies information associated with the requester describing the SAML attributes the
|
57
|
+
# requester desires or requires to be supplied by the identity provider in the <Response> message. The
|
58
|
+
# identity provider MUST have a trusted means to map the index value in the attribute to information
|
59
|
+
# associated with the requester.
|
60
|
+
attr_accessor :attribute_consuming_service_url
|
61
|
+
|
62
|
+
# Specifies the human-readable name of the requester for use by the presenter's user agent or the
|
63
|
+
# identity provider
|
64
|
+
attr_accessor :provider_name
|
65
|
+
|
66
|
+
# Validate the authentication request.
|
67
|
+
def validate
|
68
|
+
raise ValidationError, "Conditions must be of type Conditions" if conditions && !conditions.is_a?(Conditions)
|
69
|
+
end
|
70
|
+
|
71
|
+
# Construct an XML fragment representing the authentication request
|
72
|
+
def to_xml(xml=Builder::XmlMarkup.new)
|
73
|
+
attributes = {}
|
74
|
+
attributes['ForceAuthn'] = force_authn unless force_authn.nil?
|
75
|
+
attributes['IsPassive'] = is_passive unless is_passive.nil?
|
76
|
+
# TODO implement assertion consumer service index
|
77
|
+
# TODO implement assertion consumer service URL
|
78
|
+
attributes['ProtocolBinding'] = protocol_binding unless protocol_binding.nil?
|
79
|
+
attributes['AttributeConsumingServiceURL'] = attribute_consuming_service_url unless attribute_consuming_service_url.nil?
|
80
|
+
attributes['ProviderName'] = provider_name unless provider_name.nil?
|
81
|
+
xml.tag!('samlp:AuthnRequest', attributes) {
|
82
|
+
xml << subject.to_xml unless subject.nil?
|
83
|
+
xml << name_id_policy.to_xml unless name_id_policy.nil?
|
84
|
+
xml << conditions.to_xml unless conditions.nil?
|
85
|
+
xml << requested_authn_context unless requested_authn_context.nil?
|
86
|
+
xml << scoping.to_xml unless scoping.nil?
|
87
|
+
}
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module RSAML #:nodoc:
|
2
|
+
module Protocol #:nodoc:
|
3
|
+
class IDPEntry
|
4
|
+
attr_accessor :provider_id
|
5
|
+
|
6
|
+
# Initialize the IDP entry
|
7
|
+
def initialize(provider_id)
|
8
|
+
@provider_id = provider_id
|
9
|
+
end
|
10
|
+
|
11
|
+
# Construct an XML fragment representing the idp list
|
12
|
+
def to_xml(xml=Builder::XmlMarkup.new)
|
13
|
+
attributes = {'ProviderID' => provider_id}
|
14
|
+
xml.tag!('samlp:IDPEntry', attributes)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module RSAML #:nodoc:
|
2
|
+
module Protocol #:nodoc:
|
3
|
+
# Specifies the identity providers trusted by the requester to authenticate the presenter.
|
4
|
+
class IDPList
|
5
|
+
# Initialize the IDP list
|
6
|
+
def initialize(*idp_entries)
|
7
|
+
@idp_entries = idp_entries
|
8
|
+
end
|
9
|
+
|
10
|
+
# Information about identity providers.
|
11
|
+
def idp_entries
|
12
|
+
@idp_entries ||= []
|
13
|
+
end
|
14
|
+
|
15
|
+
# Validate the IDPList structure.
|
16
|
+
def validate
|
17
|
+
raise ValidationError, "At least one IDP entry is required" if idp_entries.empty?
|
18
|
+
end
|
19
|
+
|
20
|
+
# Construct an XML fragment representing the idp list
|
21
|
+
def to_xml(xml=Builder::XmlMarkup.new)
|
22
|
+
xml.tag!('samlp:IDPList') {
|
23
|
+
idp_entries.each { |idp_entry| xml << idp_entry.to_xml }
|
24
|
+
}
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
module RSAML #:nodoc:
|
2
|
+
module Protocol #:nodoc:
|
3
|
+
# Base class for messages. This class should not be instantiated directly, rather the Request and Response
|
4
|
+
# classes should be used.
|
5
|
+
class Message
|
6
|
+
|
7
|
+
# An identifier for the message. It is of type xs:ID and MUST follow the requirements specified in Section
|
8
|
+
# 1.3.4 of the SAML 2.0 specification for identifier uniqueness.
|
9
|
+
attr_accessor :id
|
10
|
+
|
11
|
+
# The version of this message. The identifier for the version of SAML defined in this specification is "2.0".
|
12
|
+
attr_accessor :version
|
13
|
+
|
14
|
+
# The time instant of issue of the message. The time value must be encoded in UTC.
|
15
|
+
attr_accessor :issue_instant
|
16
|
+
|
17
|
+
# A URI reference indicating the address to which this message has been sent. This is useful to prevent
|
18
|
+
# malicious forwarding of messages to unintended recipients, a protection that is required by some
|
19
|
+
# protocol bindings. If it is present, the actual recipient MUST check that the URI reference identifies the
|
20
|
+
# location at which the message was sent or received. If it does not, the response MUST be discarded. Some
|
21
|
+
# protocol bindings may require the use of this attribute.
|
22
|
+
attr_accessor :destination
|
23
|
+
|
24
|
+
# Indicates whether or not (and under what conditions) consent has been obtained from a principal in
|
25
|
+
# the sending of this message. If no Consent value is provided, the identifier
|
26
|
+
# urn:oasis:names:tc:SAML:2.0:consent:unspecified is in effect.
|
27
|
+
attr_accessor :consent
|
28
|
+
|
29
|
+
# Identifies the entity that generated the message.
|
30
|
+
attr_accessor :issuer
|
31
|
+
|
32
|
+
# An XML Signature that authenticates the requestor or responder and provides message integrity.
|
33
|
+
attr_accessor :signature
|
34
|
+
|
35
|
+
# Initialize the message instance
|
36
|
+
def initialize
|
37
|
+
@id = UUID.new.generate
|
38
|
+
@version = "2.0"
|
39
|
+
@issue_instant = Time.now.utc
|
40
|
+
end
|
41
|
+
|
42
|
+
# This extension point contains optional protocol message extension elements that are agreed on
|
43
|
+
# between the communicating parties.
|
44
|
+
def extensions
|
45
|
+
@extionsion ||= []
|
46
|
+
end
|
47
|
+
|
48
|
+
# Validate the request structure
|
49
|
+
def validate
|
50
|
+
raise ValidationError, "ID is required" if id.nil?
|
51
|
+
raise ValidationError, "Version is required" if version.nil?
|
52
|
+
raise ValidationError, "Issue instant is required" if issue_instant.nil?
|
53
|
+
raise ValidationError, "Issue instant must be UTC" unless issue_instant.utc?
|
54
|
+
end
|
55
|
+
|
56
|
+
protected
|
57
|
+
# Add XML Namespace attributes
|
58
|
+
def add_xmlns(attributes)
|
59
|
+
attributes['xmlns:samlp'] = "urn:oasis:names:tc:SAML:2.0:protocol"
|
60
|
+
attributes['xmlns:saml'] = "urn:oasis:names:tc:SAML:2.0:assertion"
|
61
|
+
attributes
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module RSAML #:nodoc:
|
2
|
+
module Protocol #:nodoc:
|
3
|
+
# Tailors the name identifier in the subjects of assertions resulting from an authentication request.
|
4
|
+
class NameIdPolicy
|
5
|
+
# Specifies the URI reference corresponding to a name identifier format
|
6
|
+
attr_accessor :format
|
7
|
+
|
8
|
+
# Optionally specifies that the assertion subject's identifier be returned (or created) in the namespace of
|
9
|
+
# a service provider other than the requester, or in the namespace of an affiliation group of service
|
10
|
+
# providers.
|
11
|
+
attr_accessor :sp_name_qualifier
|
12
|
+
|
13
|
+
# A Boolean value used to indicate whether the identity provider is allowed, in the course of fulfilling the
|
14
|
+
# request, to create a new identifier to represent the principal. Defaults to "false". When "false", the
|
15
|
+
# requester constrains the identity provider to only issue an assertion to it if an acceptable identifier for
|
16
|
+
# the principal has already been established. Note that this does not prevent the identity provider from
|
17
|
+
# creating such identifiers outside the context of this specific request (for example, in advance for a
|
18
|
+
# large number of principals).
|
19
|
+
attr_accessor :allow_create
|
20
|
+
|
21
|
+
# Construct an XML fragment representing the name id policy
|
22
|
+
def to_xml(xml=Builder::XmlMarkup.new)
|
23
|
+
attributes = {}
|
24
|
+
attributes['Format'] = format unless format.nil?
|
25
|
+
attributes['SPNameQualifier'] = sp_name_qualifier unless sp_name_qualifier.nil?
|
26
|
+
attributes['AllowCreate'] = allow_create unless allow_create.nil?
|
27
|
+
xml.tag!('samlp:NameIDPolicy', attributes)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module RSAML #:nodoc:
|
2
|
+
module Protocol #:nodoc:
|
3
|
+
# Module containing SAML query classes.
|
4
|
+
module Query
|
5
|
+
end
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
require 'rsaml/protocol/query/subject_query'
|
10
|
+
require 'rsaml/protocol/query/authn_query'
|
11
|
+
require 'rsaml/protocol/query/attribute_query'
|
12
|
+
require 'rsaml/protocol/query/authz_decision_query'
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module RSAML #:nodoc:
|
2
|
+
module Protocol #:nodoc:
|
3
|
+
module Query #:nodoc:
|
4
|
+
# used to make the query "Return the requested attributes for this subject." A successful response
|
5
|
+
# will be in the form of assertions containing attribute statements, to the extent allowed by policy.
|
6
|
+
class AttributeQuery < SubjectQuery
|
7
|
+
# Each attribute element specifies an attribute whose value(s) are to be returned. If no
|
8
|
+
# attributes are specified, it indicates that all attributes allowed by policy are requested.
|
9
|
+
# If a given attribute element contains one or more AttributeValue elements, then if that attribute
|
10
|
+
# is returned in the response, it MUST NOT contain any values that are not equal to the values
|
11
|
+
# specified in the query. In the absence of equality rules specified by particular profiles or
|
12
|
+
# attributes, equality is defined as an identical XML representation of the value. Each value in
|
13
|
+
# the array MUST be an Attribute instance.
|
14
|
+
def attributes
|
15
|
+
@attributes ||= []
|
16
|
+
end
|
17
|
+
|
18
|
+
# Validate the structure of the attribute query.
|
19
|
+
def validate
|
20
|
+
matched = {}
|
21
|
+
duplicated_attributes = []
|
22
|
+
attributes.each do |attribute|
|
23
|
+
if matched.has_key?(attribute.name) && matched[attribute.name] == attribute.name_format
|
24
|
+
duplicated_attributes << attribute.name unless duplicated_attributes.include?(attribute.name)
|
25
|
+
else
|
26
|
+
matched[attribute.name] = attribute.name_format
|
27
|
+
end
|
28
|
+
end
|
29
|
+
if !duplicated_attributes.empty?
|
30
|
+
raise ValidationError, "An attribute with the same name and name format may only be specified once. The following attributes were specified multiple times: #{duplicated_attributes.join(',')}"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# Construct an XML fragment representing the attribute query
|
35
|
+
def to_xml(xml=Builder::XmlMarkup.new)
|
36
|
+
xml_attributes = {}
|
37
|
+
xml.tag!('samlp:AttributeQuery', xml_attributes) {
|
38
|
+
xml << subject.to_xml unless subject.nil?
|
39
|
+
attributes.each { |attribute| xml << attribute.to_xml }
|
40
|
+
}
|
41
|
+
end
|
42
|
+
|
43
|
+
# Construct an AttributeQuery instance from the XML Element.
|
44
|
+
def self.from_xml(element)
|
45
|
+
element = REXML::Document.new(element).root if element.is_a?(String)
|
46
|
+
subject = Subject.from_xml(element.get_elements('saml:Subject').first)
|
47
|
+
attribute_query = AttributeQuery.new(subject)
|
48
|
+
element.get_elements('saml:Attribute').each do |attribute_element|
|
49
|
+
attribute_query.attributes << Attribute.from_xml(attribute_element)
|
50
|
+
end
|
51
|
+
attribute_query
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|