rsaml 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|