scashin133-rsaml 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (102) hide show
  1. data/.autotest +10 -0
  2. data/.gitignore +2 -0
  3. data/LICENSE +0 -0
  4. data/README +13 -0
  5. data/Rakefile +141 -0
  6. data/lib/rsaml/action.rb +57 -0
  7. data/lib/rsaml/action_namespace.rb +63 -0
  8. data/lib/rsaml/advice.rb +34 -0
  9. data/lib/rsaml/assertion.rb +192 -0
  10. data/lib/rsaml/attribute.rb +76 -0
  11. data/lib/rsaml/audience.rb +19 -0
  12. data/lib/rsaml/authentication_context.rb +34 -0
  13. data/lib/rsaml/authn_context/README +1 -0
  14. data/lib/rsaml/authn_context/authentication_context_declaration.rb +42 -0
  15. data/lib/rsaml/authn_context/identification.rb +10 -0
  16. data/lib/rsaml/authn_context/physical_verification.rb +24 -0
  17. data/lib/rsaml/condition.rb +13 -0
  18. data/lib/rsaml/conditions.rb +107 -0
  19. data/lib/rsaml/encrypted.rb +12 -0
  20. data/lib/rsaml/errors.rb +16 -0
  21. data/lib/rsaml/evidence.rb +21 -0
  22. data/lib/rsaml/ext/string.rb +5 -0
  23. data/lib/rsaml/identifier/base.rb +23 -0
  24. data/lib/rsaml/identifier/issuer.rb +28 -0
  25. data/lib/rsaml/identifier/name.rb +55 -0
  26. data/lib/rsaml/identifier.rb +9 -0
  27. data/lib/rsaml/parser.rb +23 -0
  28. data/lib/rsaml/protocol/artifact_resolve.rb +14 -0
  29. data/lib/rsaml/protocol/assertion_id_request.rb +18 -0
  30. data/lib/rsaml/protocol/authn_request.rb +91 -0
  31. data/lib/rsaml/protocol/idp_entry.rb +18 -0
  32. data/lib/rsaml/protocol/idp_list.rb +28 -0
  33. data/lib/rsaml/protocol/message.rb +65 -0
  34. data/lib/rsaml/protocol/name_id_policy.rb +31 -0
  35. data/lib/rsaml/protocol/query/attribute_query.rb +56 -0
  36. data/lib/rsaml/protocol/query/authn_query.rb +30 -0
  37. data/lib/rsaml/protocol/query/authz_decision_query.rb +40 -0
  38. data/lib/rsaml/protocol/query/subject_query.rb +22 -0
  39. data/lib/rsaml/protocol/query.rb +12 -0
  40. data/lib/rsaml/protocol/request.rb +27 -0
  41. data/lib/rsaml/protocol/requested_authn_context.rb +34 -0
  42. data/lib/rsaml/protocol/response.rb +56 -0
  43. data/lib/rsaml/protocol/scoping.rb +33 -0
  44. data/lib/rsaml/protocol/status.rb +38 -0
  45. data/lib/rsaml/protocol/status_code.rb +84 -0
  46. data/lib/rsaml/protocol.rb +21 -0
  47. data/lib/rsaml/proxy_restriction.rb +30 -0
  48. data/lib/rsaml/statement/attribute_statement.rb +27 -0
  49. data/lib/rsaml/statement/authentication_statement.rb +57 -0
  50. data/lib/rsaml/statement/authorization_decision_statement.rb +53 -0
  51. data/lib/rsaml/statement/base.rb +9 -0
  52. data/lib/rsaml/statement.rb +10 -0
  53. data/lib/rsaml/subject.rb +37 -0
  54. data/lib/rsaml/subject_confirmation.rb +34 -0
  55. data/lib/rsaml/subject_confirmation_data.rb +45 -0
  56. data/lib/rsaml/subject_locality.rb +27 -0
  57. data/lib/rsaml/validatable.rb +21 -0
  58. data/lib/rsaml/version.rb +9 -0
  59. data/lib/rsaml.rb +51 -0
  60. data/lib/xml_enc.rb +3 -0
  61. data/lib/xml_sig/canonicalization_method.rb +43 -0
  62. data/lib/xml_sig/key_info.rb +55 -0
  63. data/lib/xml_sig/reference.rb +57 -0
  64. data/lib/xml_sig/signature.rb +29 -0
  65. data/lib/xml_sig/signature_method.rb +20 -0
  66. data/lib/xml_sig/signed_info.rb +27 -0
  67. data/lib/xml_sig/transform.rb +37 -0
  68. data/lib/xml_sig.rb +11 -0
  69. data/scashin133-rsaml.gemspec +180 -0
  70. data/test/action_namespace_test.rb +93 -0
  71. data/test/action_test.rb +51 -0
  72. data/test/advice_test.rb +25 -0
  73. data/test/assertion_test.rb +192 -0
  74. data/test/attribute_test.rb +60 -0
  75. data/test/authentication_context_test.rb +26 -0
  76. data/test/conditions_test.rb +84 -0
  77. data/test/evidence_test.rb +33 -0
  78. data/test/identifier_test.rb +22 -0
  79. data/test/issuer_test.rb +32 -0
  80. data/test/name_test.rb +32 -0
  81. data/test/parser_test.rb +32 -0
  82. data/test/protocol/assertion_id_request_test.rb +19 -0
  83. data/test/protocol/attribute_query_test.rb +30 -0
  84. data/test/protocol/authn_query_test.rb +20 -0
  85. data/test/protocol/authn_request_test.rb +56 -0
  86. data/test/protocol/authz_decision_query_test.rb +31 -0
  87. data/test/protocol/idp_list_test.rb +15 -0
  88. data/test/protocol/request_test.rb +66 -0
  89. data/test/protocol/response_test.rb +68 -0
  90. data/test/protocol/scoping_test.rb +20 -0
  91. data/test/protocol/status_code_test.rb +34 -0
  92. data/test/protocol/status_test.rb +16 -0
  93. data/test/proxy_restriction_test.rb +20 -0
  94. data/test/rsaml_test.rb +12 -0
  95. data/test/sample_data/attribute_query.xml +8 -0
  96. data/test/statement_test.rb +101 -0
  97. data/test/subject_locality_test.rb +27 -0
  98. data/test/subject_test.rb +44 -0
  99. data/test/test_helper.rb +16 -0
  100. data/test/xml_sig/canonicalization_test.rb +19 -0
  101. data/test/xml_sig/iso-8859-1.txt +1 -0
  102. metadata +206 -0
@@ -0,0 +1,42 @@
1
+ module RSAML #:nodoc:
2
+ module AuthnContext #:nodoc:
3
+ # A particular assertion on an identity provider's part with respect to the authentication
4
+ # context associated with an authentication assertion.
5
+ class AuthenticationContextDeclaration
6
+ # Authentication method, a required attribute
7
+ attr_accessor :authn_method
8
+
9
+ # Optional ID for the authentication context declaration
10
+ attr_accessor :id
11
+
12
+ def initialize(authn_method)
13
+ @authn_method = authn_method
14
+ end
15
+
16
+ def identification
17
+ @identification ||= []
18
+ end
19
+
20
+ def technical_protection
21
+ @technical_protection ||= []
22
+ end
23
+
24
+ def operational_protection
25
+ @operational_protection ||= []
26
+ end
27
+
28
+ def governing_agreements
29
+ @governing_agreements ||= []
30
+ end
31
+
32
+ def extensions
33
+ @extensions ||= []
34
+ end
35
+
36
+ # Construct an XML fragment representing the assertion
37
+ def to_xml(xml=Builder::XmlMarkup.new)
38
+ xml.tag!('AuthContextDecl')
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,10 @@
1
+ module RSAML #:nodoc:
2
+ module AuthnContext #:nodoc:
3
+ # Refers to those characteristics that describe the processes and mechanisms the
4
+ # Authentication Authority uses to initially create an association between a Principal
5
+ # and the identity (or name) by which the Principal will be known
6
+ class Identification
7
+
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,24 @@
1
+ module RSAML #:nodoc:
2
+ module AuthnContext #:nodoc:
3
+ # This element indicates that identification has been performed in a physical
4
+ # face-to-face meeting with the principal and not in an online manner.
5
+ class PhysicalVerification
6
+ # Hash of available credential levels
7
+ def self.credential_levels
8
+ {
9
+ :primary => 'primary',
10
+ :secondary => 'secondary'
11
+ }
12
+ end
13
+
14
+ attr_accessor :credential_level
15
+
16
+ # Create an XML representation
17
+ def to_xml(xml=Builder::XmlMarkup.new)
18
+ attributes = {}
19
+ attributes['credentialLevel'] = credential_level unless credential_level.nil?
20
+ xml.tag!('PhysicalVerification', attributes)
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,13 @@
1
+ module RSAML #:nodoc
2
+ # Base class for conditions
3
+ class Condition
4
+ # Assert that the condition evaluates to true, raise an AssertionError if not
5
+ def assert
6
+ end
7
+
8
+ # Construct an XML fragment representing the condition
9
+ def to_xml(xml=Builder::XmlMarkup.new)
10
+ xml.tag!('saml:Condition')
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,107 @@
1
+ module RSAML #:nodoc:
2
+ # Constraints on the acceptable use of SAML assertions.
3
+ class Conditions
4
+ # Specifies the earliest time instant at which the assertion is valid. The time value is encoded in UTC.
5
+ attr_accessor :not_before
6
+
7
+ # Specifies the time instant at which the assertion has expired. The time value is encoded in UTC.
8
+ attr_accessor :not_on_or_after
9
+
10
+ # Specifies that the assertion SHOULD be used immediately and MUST NOT be retained for future
11
+ # use.
12
+ attr_accessor :one_time_use
13
+
14
+ # Specifies limitations that the asserting party imposes on relying parties that wish to subsequently act
15
+ # as asserting parties themselves and issue assertions of their own on the basis of the information
16
+ # contained in the original assertion.
17
+ attr_accessor :proxy_restriction
18
+
19
+ # The conditions
20
+ def conditions
21
+ @conditions ||= []
22
+ end
23
+
24
+ # Alias to access the embedded conditions array.
25
+ def []
26
+ conditions
27
+ end
28
+
29
+ # Append a condition to the conditions
30
+ def <<(condition)
31
+ conditions << condition
32
+ end
33
+
34
+ # The number of conditions
35
+ def length
36
+ conditions.length
37
+ end
38
+
39
+ # Return true if the conditions collection is empty
40
+ def empty?
41
+ conditions.length == 0
42
+ end
43
+
44
+ # Specifies that the assertion is addressed to a particular audience.
45
+ # Audiences are represented as A URI reference that identifies an intended audience.
46
+ # A URI may reference a document that describes the terms of service for audience
47
+ # membership.
48
+ def audience_restrictions
49
+ @audience_restrictions ||= []
50
+ end
51
+
52
+ # Assert the conditions
53
+ def assert
54
+ assert_time_limits
55
+ assert_elements
56
+ end
57
+
58
+ # Validate the structure of the conditions model
59
+ def validate
60
+ if not_before && not_on_or_after && not_before >= not_on_or_after
61
+ raise ValidationError, "NotBefore after NotOnOrAfter"
62
+ end
63
+ end
64
+
65
+ # Return true if the condition allows caching of the assertion
66
+ def cache?
67
+ one_time_use.nil?
68
+ end
69
+
70
+ # Construct an XML fragment representing the conditions collection
71
+ def to_xml(xml=Builder::XmlMarkup.new)
72
+ attributes = {}
73
+ attributes['NotBefore'] = not_before.xmlschema unless not_before.nil?
74
+ attributes['NotOnOrAfter'] = not_on_or_after.xmlschema unless not_on_or_after.nil?
75
+ xml.tag!('saml:Conditions', attributes) {
76
+ conditions.each { |condition| xml << condition.to_xml }
77
+ audience_restrictions.each do |audience|
78
+ xml.tag!('saml:AudienceRestriction') { xml << audience.to_xml }
79
+ end
80
+ xml.tag!('OneTimeUse') if one_time_use
81
+ xml << proxy_restriction.to_xml unless proxy_restriction.nil?
82
+ }
83
+ end
84
+
85
+ protected
86
+ # Check the the current time falls within the allowed time constraints
87
+ def assert_time_limits
88
+ raise AssertionError, "Condition failed: not before" if not_before && Time.now < not_before
89
+ raise AssertionError, "Condition failed: not on or after" if not_on_or_after && Time.now >= not_on_or_after
90
+ end
91
+
92
+ # Assert that the conditions evaluate to true
93
+ def assert_elements
94
+ # Rule 1
95
+ if conditions.empty? && audience_restrictions.empty? && proxy_restriction.nil? && one_time_use.nil?
96
+ return
97
+ end
98
+
99
+ # Rule 2
100
+ conditions.all { |c| c.assert }
101
+
102
+ # Rule 3
103
+
104
+ # Rule 4
105
+ end
106
+ end
107
+ end
@@ -0,0 +1,12 @@
1
+ module RSAML #:nodoc:
2
+ # Base for encrypted elements
3
+ class Encrypted
4
+ # Encrypted data
5
+ attr_accessor :encrypted_data
6
+
7
+ # Encrypted keys
8
+ def encrypted_keys
9
+ @encrypted_keys ||= []
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,16 @@
1
+ module RSAML #:nodoc:
2
+ # An error that is raised when a validation error occurs. Note that validity in the case
3
+ # of this library is for validity of the structure of the model according to the rules
4
+ # of the SAML 2.0 specification.
5
+ class ValidationError < StandardError
6
+ end
7
+ # An error that is raised when an assertion fails.
8
+ class AssertionError < StandardError
9
+ end
10
+ # An error that is raised when a confirmation fails.
11
+ class ConfirmationError < StandardError
12
+ end
13
+ # An error that is raised when parsing fails.
14
+ class ParseError < StandardError
15
+ end
16
+ end
@@ -0,0 +1,21 @@
1
+ module RSAML #:nodoc:
2
+ # Contains one or more assertions or assertion references that the SAML authority relied
3
+ # on in issuing the authorization decision.
4
+ class Evidence
5
+ # Specifies an assertion either by reference or by value.
6
+ def assertions
7
+ @assertions ||= []
8
+ end
9
+
10
+ def validate
11
+ raise ValidationError, "At least one assertion is required" if assertions.empty?
12
+ end
13
+
14
+ # Construct an XML fragment representing the authentication statement
15
+ def to_xml(xml=Builder::XmlMarkup.new)
16
+ xml.tag!('saml:Evidence') {
17
+ assertions.each { |assertion| xml << assertion.to_xml }
18
+ }
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,5 @@
1
+ class String #:nodoc:
2
+ def to_xml
3
+ to_s
4
+ end
5
+ end
@@ -0,0 +1,23 @@
1
+ module RSAML #:nodoc:
2
+ module Identifier # :nodoc:
3
+ # An extension point that allows applications to add new kinds of identifiers.
4
+ class Base
5
+ # The security or administrative domain that qualifies the name. This attribute provides a means to
6
+ # federate names from disparate user stores without collision.
7
+ attr_accessor :name_qualifier
8
+
9
+ # Further qualifies a name with the name of a service provider or affiliation of providers. This
10
+ # attribute provides an additional means to federate names on the basis of the relying party or
11
+ # parties.
12
+ attr_accessor :sp_name_qualifier
13
+
14
+ # Create an XML fragment representing the identifier
15
+ def to_xml(xml=Builder::XmlMarkup.new)
16
+ attributes = {}
17
+ attributes['NameQualifier'] = name_qualifier unless name_qualifier.nil?
18
+ attributes['SPNameQualifier'] = sp_name_qualifier unless sp_name_qualifier.nil?
19
+ xml.tag!('saml:BaseID', '', attributes)
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,28 @@
1
+ module RSAML #:nodoc:
2
+ module Identifier #:nodoc:
3
+ # provides information about the issuer of a SAML assertion or protocol message. T
4
+ # Requires the use of a string to carry the issuer's name
5
+ class Issuer < Name
6
+ # If no Format value is provided with this element, then the value
7
+ # urn:oasis:names:tc:SAML:2.0:nameid-format:entity is in effect
8
+ def format
9
+ @format ||= Name.formats[:entity]
10
+ end
11
+
12
+ # Construct an XML fragment representing the issuer
13
+ def to_xml(xml=Builder::XmlMarkup.new)
14
+ attributes = {'Format' => format}
15
+ attributes['NameQualifier'] = name_qualifier unless name_qualifier.nil?
16
+ attributes['SPNameQualifier'] = sp_name_qualifier unless sp_name_qualifier.nil?
17
+ attributes['SPProvidedID'] = sp_provided_id unless sp_provided_id.nil?
18
+ xml.tag!('saml:Issuer', value, attributes)
19
+ end
20
+
21
+ # Construct an Issuer instance from the given XML Element or fragment.
22
+ def self.from_xml(element)
23
+ element = REXML::Document.new(element).root if element.is_a?(String)
24
+ Issuer.new(element.text)
25
+ end
26
+ end
27
+ end
28
+ end
@@ -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
@@ -0,0 +1,9 @@
1
+ module RSAML #:nodoc:
2
+ # Module that contains various SAML identifier types.
3
+ module Identifier
4
+ end
5
+ end
6
+
7
+ require 'rsaml/identifier/base'
8
+ require 'rsaml/identifier/name'
9
+ require 'rsaml/identifier/issuer'
@@ -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,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
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