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.
Files changed (97) hide show
  1. data/LICENSE +0 -0
  2. data/README +13 -0
  3. data/Rakefile +136 -0
  4. data/lib/rsaml.rb +57 -0
  5. data/lib/rsaml/action.rb +57 -0
  6. data/lib/rsaml/action_namespace.rb +63 -0
  7. data/lib/rsaml/advice.rb +34 -0
  8. data/lib/rsaml/assertion.rb +192 -0
  9. data/lib/rsaml/attribute.rb +76 -0
  10. data/lib/rsaml/audience.rb +19 -0
  11. data/lib/rsaml/authentication_context.rb +34 -0
  12. data/lib/rsaml/authn_context/README +1 -0
  13. data/lib/rsaml/authn_context/authentication_context_declaration.rb +42 -0
  14. data/lib/rsaml/authn_context/identification.rb +10 -0
  15. data/lib/rsaml/authn_context/physical_verification.rb +24 -0
  16. data/lib/rsaml/condition.rb +13 -0
  17. data/lib/rsaml/conditions.rb +107 -0
  18. data/lib/rsaml/encrypted.rb +12 -0
  19. data/lib/rsaml/errors.rb +16 -0
  20. data/lib/rsaml/evidence.rb +21 -0
  21. data/lib/rsaml/ext/string.rb +5 -0
  22. data/lib/rsaml/identifier.rb +9 -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/parser.rb +23 -0
  27. data/lib/rsaml/protocol.rb +21 -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.rb +12 -0
  36. data/lib/rsaml/protocol/query/attribute_query.rb +56 -0
  37. data/lib/rsaml/protocol/query/authn_query.rb +30 -0
  38. data/lib/rsaml/protocol/query/authz_decision_query.rb +40 -0
  39. data/lib/rsaml/protocol/query/subject_query.rb +22 -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/proxy_restriction.rb +30 -0
  47. data/lib/rsaml/statement.rb +10 -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/subject.rb +37 -0
  53. data/lib/rsaml/subject_confirmation.rb +35 -0
  54. data/lib/rsaml/subject_confirmation_data.rb +55 -0
  55. data/lib/rsaml/subject_locality.rb +27 -0
  56. data/lib/rsaml/validatable.rb +21 -0
  57. data/lib/rsaml/version.rb +9 -0
  58. data/lib/xml_enc.rb +3 -0
  59. data/lib/xml_sig.rb +11 -0
  60. data/lib/xml_sig/canonicalization_method.rb +43 -0
  61. data/lib/xml_sig/key_info.rb +55 -0
  62. data/lib/xml_sig/reference.rb +57 -0
  63. data/lib/xml_sig/signature.rb +29 -0
  64. data/lib/xml_sig/signature_method.rb +20 -0
  65. data/lib/xml_sig/signed_info.rb +27 -0
  66. data/lib/xml_sig/transform.rb +37 -0
  67. data/test/action_namespace_test.rb +93 -0
  68. data/test/action_test.rb +51 -0
  69. data/test/advice_test.rb +25 -0
  70. data/test/assertion_test.rb +192 -0
  71. data/test/attribute_test.rb +60 -0
  72. data/test/authentication_context_test.rb +26 -0
  73. data/test/conditions_test.rb +84 -0
  74. data/test/evidence_test.rb +33 -0
  75. data/test/identifier_test.rb +22 -0
  76. data/test/issuer_test.rb +33 -0
  77. data/test/name_test.rb +33 -0
  78. data/test/parser_test.rb +32 -0
  79. data/test/protocol/assertion_id_request_test.rb +19 -0
  80. data/test/protocol/attribute_query_test.rb +30 -0
  81. data/test/protocol/authn_query_test.rb +20 -0
  82. data/test/protocol/authn_request_test.rb +56 -0
  83. data/test/protocol/authz_decision_query_test.rb +31 -0
  84. data/test/protocol/idp_list_test.rb +15 -0
  85. data/test/protocol/request_test.rb +66 -0
  86. data/test/protocol/response_test.rb +68 -0
  87. data/test/protocol/scoping_test.rb +20 -0
  88. data/test/protocol/status_code_test.rb +34 -0
  89. data/test/protocol/status_test.rb +16 -0
  90. data/test/proxy_restriction_test.rb +20 -0
  91. data/test/rsaml_test.rb +12 -0
  92. data/test/statement_test.rb +101 -0
  93. data/test/subject_locality_test.rb +27 -0
  94. data/test/subject_test.rb +44 -0
  95. data/test/test_helper.rb +16 -0
  96. data/test/xml_sig/canonicalization_test.rb +19 -0
  97. metadata +187 -0
@@ -0,0 +1,76 @@
1
+ module RSAML #:nodoc:
2
+ # Identifies an attribute by name and optionally includes its value(s).
3
+ class Attribute
4
+ # The name of the attribute.
5
+ attr_accessor :name
6
+
7
+ # A URI reference representing the classification of the attribute name for purposes of
8
+ # interpreting the name
9
+ attr_accessor :name_format
10
+
11
+ # A string that provides a more human-readable form of the attribute's name, which may
12
+ # be useful in cases in which the actual Name is complex or opaque, such as an OID or a UUID.
13
+ attr_accessor :friendly_name
14
+
15
+ # Initialize the attribute with the given name. Optionally pass an array of values.
16
+ def initialize(name, *values)
17
+ @name = name
18
+ @values = values
19
+ end
20
+
21
+ # An array of values for the attribute.
22
+ def values
23
+ @values ||= []
24
+ end
25
+
26
+ # Validate the structure of the attribute.
27
+ def validate
28
+ raise ValidationError, "Name is required" unless name
29
+ end
30
+
31
+ # extension point to allow arbitrary XML attributes to be added to <Attribute> constructs
32
+ # without the need for an explicit schema extension. This allows additional fields to be
33
+ # added as needed to supply additional parameters to be used, for example, in an attribute
34
+ # query. This attribute is a Hash of name/value pairs that is output directly with the
35
+ # <Attribute> XML element.
36
+ def extra_xml_attributes
37
+ @extra_xml_attributes ||= {}
38
+ end
39
+
40
+ # Construct an XML fragment representing the attribute
41
+ def to_xml(xml=Builder::XmlMarkup.new)
42
+ xml_attributes = {'Name' => name}
43
+ xml_attributes['NameFormat'] = name_format unless name_format.nil?
44
+ xml_attributes['FriendlyName'] = friendly_name unless friendly_name.nil?
45
+ xml.tag!('saml:Attribute', xml_attributes.merge(extra_xml_attributes)) {
46
+ values.each { |value| xml.tag!('saml:AttributeValue', value.to_s) }
47
+ }
48
+ end
49
+
50
+ def self.from_xml(element)
51
+ element = REXML::Document.new(element).root if element.is_a?(String)
52
+ attribute = Attribute.new(element.attribute('Name').value)
53
+ if element.attribute('NameFormat')
54
+ attribute.name_format = element.attribute('NameFormat').value
55
+ end
56
+ attribute
57
+ end
58
+ end
59
+
60
+ # An encrypted attribute.
61
+ class EncryptedAttribute < Encrypted
62
+
63
+ # Validate the structure
64
+ def validate
65
+ raise ValidationError, "Encrypted data is required" if encrypted_data.nil?
66
+ end
67
+
68
+ # Construct an XML fragment representing the encrypted attribute
69
+ def to_xml(xml=Builder::XmlMarkup.new)
70
+ xml.tag!('saml:EncryptedAttribute') {
71
+ xml.tag!('xenc:EncryptedData', encrypted_data)
72
+ encrypted_keys.each { |key| xml << key.to_xml }
73
+ }
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,19 @@
1
+ module RSAML #:nodoc:
2
+ # A URI reference that identifies an intended audience. The URI reference MAY identify a document
3
+ # that describes the terms and conditions of audience membership. It MAY also contain the unique
4
+ # identifier URI from a SAML name identifier that describes a system entity.
5
+ class Audience
6
+ # URI for the audience
7
+ attr_accessor :uri
8
+
9
+ # Initialize the Audience instance with the given URI
10
+ def initialize(uri)
11
+ @uri = uri
12
+ end
13
+
14
+ # Construct an XML fragment representing the audience
15
+ def to_xml(xml=Builder::XmlMarkup.new)
16
+ xml.tag!('saml:Audience', uri)
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,34 @@
1
+ module RSAML #:nodoc:
2
+ # Specifies the context of an authentication event. The element can contain
3
+ # an authentication context class reference, an authentication context declaration
4
+ # or declaration reference, or both.
5
+ class AuthenticationContext
6
+ # A URI reference identifying an authentication context class that describes the authentication context
7
+ # declaration that follows.
8
+ attr_accessor :class_reference
9
+
10
+ # An authentication context declaration provided by value.
11
+ attr_accessor :context_declaration
12
+
13
+ # A URI reference that identifies a declaration. The URI reference MAY directly resolve into
14
+ # an XML document containing the referenced declaration.
15
+ attr_accessor :context_declaration_ref
16
+
17
+ # Zero or more unique identifiers of authentication authorities that were involved in the
18
+ # authentication of the principal
19
+ def authenticating_authority
20
+ @authenticating_authority ||= []
21
+ end
22
+
23
+ # Construct an XML fragment representing the authentication statement
24
+ def to_xml(xml=Builder::XmlMarkup.new)
25
+ xml.tag!('saml:AuthnContext') {
26
+ xml.tag!('saml:AuthnContextClassRef', class_reference) unless class_reference.nil?
27
+ xml.tag!('saml:AuthnContextDecl', context_declaration) unless context_declaration.nil?
28
+ xml.tag!('saml:AuthnContextDeclRef', context_declaration_ref) unless context_declaration_ref.nil?
29
+ }
30
+ end
31
+ end
32
+ end
33
+
34
+ require 'rsaml/authn_context/authentication_context_declaration'
@@ -0,0 +1 @@
1
+ Implementation of the AuthnContext 2.0 specification.
@@ -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 && audience_restrictions.empty?
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,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
+ 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