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,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,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
@@ -0,0 +1,30 @@
1
+ module RSAML #:nodoc:
2
+ module Protocol #:nodoc:
3
+ module Query #:nodoc:
4
+ # An AuthnQuery is used to make the query "What assertions containing authentication statements
5
+ # are available for this subject?" A successful response will contain one or more assertions containing
6
+ # authentication statements.
7
+ class AuthnQuery < SubjectQuery
8
+ # If present, specifies a filter for possible responses. Such a query asks the question "What assertions
9
+ # containing authentication statements do you have for this subject within the context of the supplied
10
+ # session information?" The value of this attribute MUST be a string.
11
+ attr_accessor :session_index
12
+
13
+ # If present, specifies a filter for possible responses. Such a query asks the question "What assertions
14
+ # containing authentication statements do you have for this subject that satisfy the authentication
15
+ # context requirements in this element?" The value of this attribute MUST be a RequestedAuthnContext
16
+ # instance.
17
+ attr_accessor :requested_authn_context
18
+
19
+ # Construct an XML fragment representing the authn query
20
+ def to_xml(xml=Builder::XmlMarkup.new)
21
+ attributes = {}
22
+ attributes['SessionIndex'] = session_index unless session_index.nil?
23
+ xml.tag!('samlp:AuthnQuery', attributes) {
24
+ xml << subject.to_xml unless subject.nil?
25
+ }
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,40 @@
1
+ # Source code for the RSAML::Protocol::Query::AuthzDecisionQuery class.
2
+
3
+ module RSAML #:nodoc:
4
+ module Protocol #:nodoc:
5
+ module Query #:nodoc:
6
+ # Used to make the query "Should these actions on this resource be allowed for this subject,
7
+ # given this evidence?" A successful response will be in the form of assertions containing
8
+ # authorization decision statements.
9
+ class AuthzDecisionQuery < SubjectQuery
10
+ # A URI reference indicating the resource for which authorization is requested.
11
+ attr_accessor :resource
12
+
13
+ # The actions for which authorization is requested.
14
+ def actions
15
+ @actions ||= []
16
+ end
17
+
18
+ # A set of assertions that the SAML authority MAY rely on in making its authorization decision.
19
+ attr_accessor :evidence
20
+
21
+ # Validate the query structure.
22
+ def validate
23
+ raise ValidationError, "Resource is required" if resource.nil?
24
+ raise ValidationError, "At least one action is required" if actions.empty?
25
+ actions.each { |action| action.validate }
26
+ end
27
+
28
+ # Construct an XML fragment representing the authorization decision query
29
+ def to_xml(xml=Builder::XmlMarkup.new)
30
+ attributes = {'Resource' => resource}
31
+ xml.tag!('samlp:AuthzDecisionQuery', attributes) {
32
+ xml << subject.to_xml unless subject.nil?
33
+ actions.each { |action| xml << action.to_xml }
34
+ xml << evidence.to_xml unless evidence.nil?
35
+ }
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,22 @@
1
+ module RSAML #:nodoc:
2
+ module Protocol #:nodoc:
3
+ module Query #:nodoc:
4
+ # Extension point that allows new SAML queries to be defined that specify a single SAML subject.
5
+ # This class should not be instantiated directly.
6
+ class SubjectQuery < RSAML::Protocol::Request
7
+ # The subject
8
+ attr_accessor :subject
9
+
10
+ # Initialize the subject query
11
+ def initialize(subject)
12
+ @subject = subject
13
+ end
14
+
15
+ # Validate the subject query structure.
16
+ def validate
17
+ raise ValidationError, "Subject is required" if subject.nil?
18
+ end
19
+ end
20
+ end
21
+ end
22
+ 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,27 @@
1
+ module RSAML #:nodoc:
2
+ module Protocol #:nodoc:
3
+ # A SAML request
4
+ class Request < Message
5
+ # Generate a Response instance with the given status code. The response's in_response_to attribute
6
+ # will be set to the ID of the request.
7
+ def respond(status)
8
+ response = Response.new(status)
9
+ response.in_response_to = id
10
+ response
11
+ end
12
+
13
+ # Construct an XML fragment representing the request
14
+ def to_xml(xml=Builder::XmlMarkup.new)
15
+ attributes = {'ID' => id, 'Version' => version, 'IssueInstant' => issue_instant.xmlschema}
16
+ attributes['Destination'] = destination unless destination.nil?
17
+ attributes['Consent'] = consent unless consent.nil?
18
+ attributes = add_xmlns(attributes)
19
+ xml.tag!('samlp:Request', attributes) {
20
+ xml << issuer.to_xml unless issuer.nil?
21
+ xml << signature.to_xml unless signature.nil?
22
+ # TODO: add extensions support
23
+ }
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,34 @@
1
+ module RSAML #:nodoc:
2
+ module Protocol #:nodoc:
3
+ # Specifies the authentication context requirements of authentication statements returned in
4
+ # response to a request or query.
5
+ class RequestedAuthnContext
6
+ # List of available comparison values
7
+ def self.comparisons
8
+ @comparisons ||= ['exact','minimum','maximum','better']
9
+ end
10
+
11
+ # Authentication context references, either AuthnContextDeclRef or AuthnContextClassRef.
12
+ def authn_context_refs
13
+ @authn_context_refs ||= []
14
+ end
15
+
16
+ # Specifies the comparison method used to evaluate the requested context classes or statements, one
17
+ # of "exact", "minimum", "maximum", or "better". The default is "exact"
18
+ def comparison
19
+ @comparison ||= 'exact'
20
+ end
21
+
22
+ # Validate the structure of the requested authn context
23
+ def validate
24
+ raise ValidationError, "Unknown comparison type: #{comparison}" unless RequestedAuthContext.comparisons.include?(comparison)
25
+ end
26
+
27
+ # Construct an XML fragment representing the requested authn context
28
+ def to_xml(xml=Builder::XmlMarkup.new)
29
+ attributes = {'Comparison' => comparison}
30
+ xml.tag!('samlp:RequestedAuthnContext')
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,56 @@
1
+ module RSAML #:nodoc:
2
+ module Protocol #:nodoc:
3
+ # A SAML response
4
+ class Response < Message
5
+ # A reference to the identifier of the request to which the response corresponds, if any. If the response
6
+ # is not generated in response to a request, or if the ID attribute value of a request cannot be
7
+ # determined (for example, the request is malformed), then this attribute MUST NOT be present.
8
+ # Otherwise, it MUST be present and its value MUST match the value of the corresponding request's
9
+ # ID attribute.
10
+ attr_accessor :in_response_to
11
+
12
+ # A code representing the status of the corresponding request.
13
+ attr_accessor :status
14
+
15
+ # Initialize the Response instance
16
+ def initialize(status)
17
+ super()
18
+ @status = status
19
+ end
20
+
21
+ # SAML assertions
22
+ def assertions
23
+ @assertions ||= []
24
+ end
25
+
26
+ # SAML encrypted assertions
27
+ def encrypted_assertions
28
+ @encrypted_assertions ||= []
29
+ end
30
+
31
+ # Validate the request structure
32
+ def validate
33
+ super
34
+ raise ValidationError, "Status must be specified" if status.nil?
35
+ raise ValidationError, "Status must be a RSAML::Protocol::Status instance" unless status.is_a?(Status)
36
+ end
37
+
38
+ # Construct an XML fragment representing the request
39
+ def to_xml(xml=Builder::XmlMarkup.new)
40
+ attributes = {'ID' => id, 'Version' => version, 'IssueInstant' => issue_instant.xmlschema}
41
+ attributes['InResponseTo'] = in_response_to unless in_response_to.nil?
42
+ attributes['Destination'] = destination unless destination.nil?
43
+ attributes['Consent'] = consent unless consent.nil?
44
+ attributes = add_xmlns(attributes)
45
+ xml.tag!('samlp:Response', attributes) {
46
+ xml << issuer.to_xml unless issuer.nil?
47
+ xml << signature.to_xml unless signature.nil?
48
+ # TODO: add extensions support
49
+ xml << status.to_xml unless status.nil?
50
+ assertions.each { |assertion| xml << assertion.to_xml }
51
+ encrypted_assertions.each { |encrypted_assertion| xml << encrypted_assertion.to_xml }
52
+ }
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,33 @@
1
+ module RSAML #:nodoc:
2
+ module Protocol #:nodoc:
3
+ # specifies the identity providers trusted by the requester to authenticate the presenter, as well as
4
+ # limitations and context related to proxying of the <AuthnRequest> message to subsequent identity
5
+ # providers by the responder.
6
+ class Scoping
7
+ # Specifies the number of proxying indirections permissible between the identity provider that receives
8
+ # this <AuthnRequest> and the identity provider who ultimately authenticates the principal. A count of
9
+ # zero permits no proxying, while omitting this attribute expresses no such restriction.
10
+ attr_accessor :proxy_count
11
+
12
+ # An advisory list of identity providers and associated information that the requester deems acceptable
13
+ # to respond to the request.
14
+ attr_accessor :idp_list
15
+
16
+ # Identifies the set of requesting entities on whose behalf the requester is acting. Used to communicate
17
+ # the chain of requesters when proxying occurs.
18
+ def requestor_ids
19
+ @requestor_ids ||= []
20
+ end
21
+
22
+ # Construct an XML fragment representing the scoping
23
+ def to_xml(xml=Builder::XmlMarkup.new)
24
+ attributes = {}
25
+ attributes['ProxyCount'] = proxy_count if proxy_count
26
+ xml.tag!('samlp:Scoping', attributes) {
27
+ xml << idp_list.to_xml if idp_list
28
+ requestor_ids.each { |requestor_id| xml << requestor_id.to_xml }
29
+ }
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,38 @@
1
+ module RSAML #:nodoc:
2
+ module Protocol #:nodoc:
3
+ # A SAML status indicator.
4
+ class Status
5
+ # A code representing the status of the activity carried out in response to the corresponding request.
6
+ attr_accessor :status_code
7
+
8
+ # A message which MAY be returned to an operator.
9
+ attr_accessor :status_message
10
+
11
+ # Initialize the status with the given status code
12
+ def initialize(status_code)
13
+ @status_code = status_code
14
+ end
15
+
16
+ # Additional information concerning the status of the request. All objects in the collection must
17
+ # respond to the to_xml method.
18
+ def status_detail
19
+ @status_detail ||= []
20
+ end
21
+
22
+ # Validate the structure of the Status instance
23
+ def validate
24
+ raise ValidationError, "Status code required" if status_code.nil?
25
+ raise ValidationError, "Status code must be a RSAML::Protocol::StatusCode instance" unless status_code.is_a?(StatusCode)
26
+ end
27
+
28
+ # Construct an XML fragment representing the request
29
+ def to_xml(xml=Builder::XmlMarkup.new)
30
+ xml.tag!('samlp:Status') {
31
+ xml << status_code.to_xml unless status_code.nil?
32
+ xml.tag!('StatusMessage', status_message) unless status_message.nil?
33
+ status_detail.each { |status_detail| xml << status_detail.to_xml }
34
+ }
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,84 @@
1
+ module RSAML #:nodoc:
2
+ module Protocol #:nodoc:
3
+ # A code or a set of nested codes representing the status of the corresponding request.
4
+ #
5
+ # More information on available status codes may be found in Section 3.2.2.2 of the SAML 2.0 Core
6
+ # specification.
7
+ class StatusCode
8
+ # Initialize the status code with the given value
9
+ def initialize(value)
10
+ @value = value
11
+ end
12
+
13
+ # Constant respresenting the Success status
14
+ SUCCESS = StatusCode.new('urn:oasis:names:tc:SAML:2.0:status:Success')
15
+
16
+ # Constant representing the Requestor status
17
+ REQUESTOR = StatusCode.new('urn:oasis:names:tc:SAML:2.0:status:Requestor')
18
+
19
+ # Constant representing the Responder status
20
+ RESPONDER = StatusCode.new('urn:oasis:names:tc:SAML:2.0:status:Responder')
21
+
22
+ # Constant representing the VersionMismatch status
23
+ VERSION_MISMATCH = StatusCode.new('urn:oasis:names:tc:SAML:2.0:status:VersionMismatch')
24
+
25
+ # Hash of symbol/StatusCode pairs representing top-level status codes.
26
+ def self.top_level_status_codes
27
+ @top_level_status_codes ||= {
28
+ :success => SUCCESS,
29
+ :requestor => REQUESTOR,
30
+ :responder => RESPONDER,
31
+ :version_mismatch => VERSION_MISMATCH
32
+ }
33
+ end
34
+
35
+ # Hash of symbol/StatusCode pairs representing second-level status codes.
36
+ def self.second_level_status_codes
37
+ @second_level_status_codes ||= {
38
+ :authn_failed => StatusCode.new('urn:oasis:names:tc:SAML:2.0:status:AuthnFailed'),
39
+ :invalid_attr_name_or_value => StatusCode.new('urn:oasis:names:tc:SAML:2.0:status:InvalidAttrNameOrValue'),
40
+ :invalid_name_id_policy => StatusCode.new('urn:oasis:names:tc:SAML:2.0:status:InvalidNameIDPolicy'),
41
+ :no_authn_context => StatusCode.new('urn:oasis:names:tc:SAML:2.0:status:NoAuthnContext'),
42
+ :no_available_idp => StatusCode.new('urn:oasis:names:tc:SAML:2.0:status:NoAvailableIDP'),
43
+ :no_passive => StatusCode.new('urn:oasis:names:tc:SAML:2.0:status:NoPassive'),
44
+ :no_supported_idp => StatusCode.new('urn:oasis:names:tc:SAML:2.0:status:NoSupportedIDP'),
45
+ :partial_logout => StatusCode.new('urn:oasis:names:tc:SAML:2.0:status:PartialLogout'),
46
+ :proxy_count_exceeded => StatusCode.new('urn:oasis:names:tc:SAML:2.0:status:ProxyCountExceeded'),
47
+ :request_denied => StatusCode.new('urn:oasis:names:tc:SAML:2.0:status:RequestDenied'),
48
+ :request_unsupported => StatusCode.new('urn:oasis:names:tc:SAML:2.0:status:RequestUnsupported'),
49
+ :request_version_deprecated => StatusCode.new('urn:oasis:names:tc:SAML:2.0:status:RequestVersionDeprecated'),
50
+ :request_version_too_high => StatusCode.new('urn:oasis:names:tc:SAML:2.0:status:RequestVersionTooHigh'),
51
+ :request_version_too_low => StatusCode.new('urn:oasis:names:tc:SAML:2.0:status:RequestVersionTooLow'),
52
+ :resource_not_recognized => StatusCode.new('urn:oasis:names:tc:SAML:2.0:status:ResourceNotRecognized'),
53
+ :too_many_responses => StatusCode.new('urn:oasis:names:tc:SAML:2.0:status:TooManyResponse'),
54
+ :unknown_attr_profile => StatusCode.new('urn:oasis:names:tc:SAML:2.0:status:UnknownAttrProfile'),
55
+ :unknown_principal => StatusCode.new('urn:oasis:names:tc:SAML:2.0:status:UnknownPrincipal'),
56
+ :unsupported_binding => StatusCode.new('urn:oasis:names:tc:SAML:2.0:status:UnsupportedBinding'),
57
+ }
58
+ end
59
+
60
+ # The status code value. Value is a URI reference.
61
+ attr_accessor :value
62
+
63
+ # An optional child status code.
64
+ attr_accessor :status_code
65
+
66
+ def validate
67
+ raise ValidationError, "Value is required" if value.nil?
68
+ end
69
+
70
+ # Construct an XML fragment representing the request
71
+ def to_xml(xml=Builder::XmlMarkup.new)
72
+ attributes = {'Value' => value}
73
+ xml.tag!('samlp:StatusCode', attributes) {
74
+ xml << status_code.to_xml unless status_code.nil?
75
+ }
76
+ end
77
+
78
+ # Return the value of the status code as a string.
79
+ def to_s
80
+ value
81
+ end
82
+ end
83
+ end
84
+ 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,30 @@
1
+ module RSAML #:nodoc:
2
+ # Specifies limitations that the asserting party imposes on relying parties that in turn wish to act as asserting
3
+ # parties and issue subsequent assertions of their own on the basis of the information contained in the
4
+ # original assertion. A relying party acting as an asserting party MUST NOT issue an assertion that itself
5
+ # violates the restrictions specified in this condition on the basis of an assertion containing such a condition.
6
+ class ProxyRestriction
7
+ # Specifies the maximum number of indirections that the asserting party permits to exist between this
8
+ # assertion and an assertion which has ultimately been issued on the basis of it.
9
+ attr_accessor :count
10
+
11
+ def audiences
12
+ @audiences ||= []
13
+ end
14
+
15
+ # Validate the structure
16
+ def validate
17
+ raise ValidationError, "Count must be 0 or more if specified" if !count.nil? && count < 0
18
+ end
19
+
20
+ # Construct an XML fragment representing the proxy restriction
21
+ def to_xml(xml=Builder::XmlMarkup.new)
22
+ attributes = {}
23
+ attributes['Count'] = count unless count.nil?
24
+ xml.tag!('saml:ProxyRestriction', attributes) {
25
+ audiences.each { |audience| xml << audience.to_xml }
26
+ }
27
+ end
28
+
29
+ end
30
+ end
@@ -0,0 +1,27 @@
1
+ module RSAML #:nodoc:
2
+ module Statement #:nodoc:
3
+ # The assertion subject is associated with the supplied attributes.
4
+ class AttributeStatement < Base
5
+ # Specifies attributes of the assertion subject.
6
+ def attributes
7
+ @attributes ||= []
8
+ end
9
+
10
+ # Validate the structure of the attribute statement. Raises a validation error if:
11
+ #
12
+ # * Has no attributes specified
13
+ # * Any of the attributes are invalid
14
+ def validate
15
+ raise ValidationError, "At least one attribute must be specified" if @attributes.empty?
16
+ @attributes.each { |attribute| attribute.validate }
17
+ end
18
+
19
+ # Construct an XML fragment representing the authentication statement
20
+ def to_xml(xml=Builder::XmlMarkup.new)
21
+ xml.tag!('saml:AttributeStatement') {
22
+ attributes.each { |attribute| xml << attribute.to_xml }
23
+ }
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,57 @@
1
+ module RSAML #:nodoc:
2
+ module Statement #:nodoc:
3
+ # The assertion subject was authenticated by a particular means at a particular time.
4
+ class AuthenticationStatement < Base
5
+ # Specifies the time at which the authentication took place. The time value is encoded in UTC
6
+ attr_accessor :authn_instant
7
+
8
+ # Specifies the index of a particular session between the principal identified by the subject and the
9
+ # authenticating authority. In general, any string value MAY be used as a SessionIndex value.
10
+ # However, when privacy is a consideration, care must be taken to ensure that the SessionIndex
11
+ # value does not invalidate other privacy mechanisms. Accordingly, the value SHOULD NOT be usable
12
+ # to correlate activity by a principal across different session participants.
13
+ attr_accessor :session_index
14
+
15
+ # Specifies a time instant at which the session between the principal identified by the subject and the
16
+ # SAML authority issuing this statement MUST be considered ended. The time value is encoded in
17
+ # UTCSpecifies
18
+ attr_accessor :session_not_on_or_after
19
+
20
+ # Specifies the DNS domain name and IP address for the system from which the assertion subject was
21
+ # apparently authenticated.
22
+ attr_accessor :subject_locality
23
+
24
+ # The authentication context.
25
+ attr_accessor :authn_context
26
+
27
+ # Initialize the statement
28
+ def initialize(authn_context)
29
+ @authn_context = authn_context
30
+ @authn_instant = Time.now.utc
31
+ end
32
+
33
+ # Validate the structure of the authentication statement. Raise a ValidationError if the
34
+ # statement is invalid.
35
+ def validate
36
+ if session_not_on_or_after && !session_not_on_or_after.utc?
37
+ raise ValidationError, "Session not on or after must be UTC"
38
+ end
39
+ raise ValidationError, "Authn context required" unless authn_context
40
+ raise ValidationError, "Authn instant required" unless authn_instant
41
+ raise ValidationError, "Authn instant must be UTC" unless authn_instant.utc?
42
+ end
43
+
44
+ # Construct an XML fragment representing the authentication statement
45
+ def to_xml(xml=Builder::XmlMarkup.new)
46
+ validate
47
+ attributes = {'AuthnInstant' => authn_instant.xmlschema}
48
+ attributes['SessionIndex'] = session_index unless session_index.nil?
49
+ attributes['SessionNotOnOrAfter'] = session_not_on_or_after.xmlschema unless session_not_on_or_after.nil?
50
+ xml.tag!('saml:AuthnStatement', attributes) {
51
+ xml << authn_context.to_xml
52
+ xml << subject_locality.to_xml unless subject_locality.nil?
53
+ }
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,53 @@
1
+ module RSAML #:nodoc:
2
+ module Statement #:nodoc:
3
+ # A request to allow the assertion subject to access the specified resource
4
+ # has been granted or denied.
5
+ class AuthorizationDecisionStatement < Base
6
+ # defines the possible values to be reported as the status of an authorization decision statement.
7
+ #
8
+ # Possible values are:
9
+ # * <tt>Permit</tt>: The specified action is permitted.
10
+ # * <tt>Deny</tt>: The specified action is denied.
11
+ # * <tt>Indeterminate</tt> The SAML authority cannot determine whether the specified action
12
+ # is permitted or denied.
13
+ def self.decision_types
14
+ %w(Permit Deny Indeterminate)
15
+ end
16
+
17
+ # A URI reference identifying the resource to which access authorization is sought.
18
+ # This attribute MAY have the value of the empty URI reference (""), and the meaning
19
+ # is defined to be "the start of the current document"
20
+ attr_accessor :resource
21
+
22
+ # The decision rendered by the SAML authority with respect to the specified resource.
23
+ attr_accessor :decision
24
+
25
+ # The set of actions authorized to be performed on the specified resource.
26
+ def actions
27
+ @actions ||= []
28
+ end
29
+
30
+ # A set of assertions that the SAML authority relied on in making the decision.
31
+ def evidence
32
+ @evidence ||= []
33
+ end
34
+
35
+ # Validate the structure
36
+ def validate
37
+ raise ValidationError, "Resource is required" if resource.nil?
38
+ raise ValidationError, "Decision is required" if decision.nil?
39
+ raise ValidationError, "One or more actions must be specified" if actions.empty?
40
+ actions.each { |action| action.validate }
41
+ end
42
+
43
+ # Construct an XML fragment representing the authorization decision statement
44
+ def to_xml(xml=Builder::XmlMarkup.new)
45
+ attributes = {'Resource' => resource, 'Decision' => decision}
46
+ xml.tag!('saml:AuthzStatement', attributes) {
47
+ actions.each { |action| xml << action.to_xml }
48
+ evidence.each { |e| xml << e.to_xml }
49
+ }
50
+ end
51
+ end
52
+ end
53
+ end