rsaml 0.1.2

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