scashin133-rsaml 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.autotest +10 -0
- data/.gitignore +2 -0
- data/LICENSE +0 -0
- data/README +13 -0
- data/Rakefile +141 -0
- data/lib/rsaml/action.rb +57 -0
- data/lib/rsaml/action_namespace.rb +63 -0
- data/lib/rsaml/advice.rb +34 -0
- data/lib/rsaml/assertion.rb +192 -0
- data/lib/rsaml/attribute.rb +76 -0
- data/lib/rsaml/audience.rb +19 -0
- data/lib/rsaml/authentication_context.rb +34 -0
- data/lib/rsaml/authn_context/README +1 -0
- data/lib/rsaml/authn_context/authentication_context_declaration.rb +42 -0
- data/lib/rsaml/authn_context/identification.rb +10 -0
- data/lib/rsaml/authn_context/physical_verification.rb +24 -0
- data/lib/rsaml/condition.rb +13 -0
- data/lib/rsaml/conditions.rb +107 -0
- data/lib/rsaml/encrypted.rb +12 -0
- data/lib/rsaml/errors.rb +16 -0
- data/lib/rsaml/evidence.rb +21 -0
- data/lib/rsaml/ext/string.rb +5 -0
- data/lib/rsaml/identifier/base.rb +23 -0
- data/lib/rsaml/identifier/issuer.rb +28 -0
- data/lib/rsaml/identifier/name.rb +55 -0
- data/lib/rsaml/identifier.rb +9 -0
- data/lib/rsaml/parser.rb +23 -0
- data/lib/rsaml/protocol/artifact_resolve.rb +14 -0
- data/lib/rsaml/protocol/assertion_id_request.rb +18 -0
- data/lib/rsaml/protocol/authn_request.rb +91 -0
- data/lib/rsaml/protocol/idp_entry.rb +18 -0
- data/lib/rsaml/protocol/idp_list.rb +28 -0
- data/lib/rsaml/protocol/message.rb +65 -0
- data/lib/rsaml/protocol/name_id_policy.rb +31 -0
- data/lib/rsaml/protocol/query/attribute_query.rb +56 -0
- data/lib/rsaml/protocol/query/authn_query.rb +30 -0
- data/lib/rsaml/protocol/query/authz_decision_query.rb +40 -0
- data/lib/rsaml/protocol/query/subject_query.rb +22 -0
- data/lib/rsaml/protocol/query.rb +12 -0
- data/lib/rsaml/protocol/request.rb +27 -0
- data/lib/rsaml/protocol/requested_authn_context.rb +34 -0
- data/lib/rsaml/protocol/response.rb +56 -0
- data/lib/rsaml/protocol/scoping.rb +33 -0
- data/lib/rsaml/protocol/status.rb +38 -0
- data/lib/rsaml/protocol/status_code.rb +84 -0
- data/lib/rsaml/protocol.rb +21 -0
- data/lib/rsaml/proxy_restriction.rb +30 -0
- data/lib/rsaml/statement/attribute_statement.rb +27 -0
- data/lib/rsaml/statement/authentication_statement.rb +57 -0
- data/lib/rsaml/statement/authorization_decision_statement.rb +53 -0
- data/lib/rsaml/statement/base.rb +9 -0
- data/lib/rsaml/statement.rb +10 -0
- data/lib/rsaml/subject.rb +37 -0
- data/lib/rsaml/subject_confirmation.rb +34 -0
- data/lib/rsaml/subject_confirmation_data.rb +45 -0
- data/lib/rsaml/subject_locality.rb +27 -0
- data/lib/rsaml/validatable.rb +21 -0
- data/lib/rsaml/version.rb +9 -0
- data/lib/rsaml.rb +51 -0
- data/lib/xml_enc.rb +3 -0
- data/lib/xml_sig/canonicalization_method.rb +43 -0
- data/lib/xml_sig/key_info.rb +55 -0
- data/lib/xml_sig/reference.rb +57 -0
- data/lib/xml_sig/signature.rb +29 -0
- data/lib/xml_sig/signature_method.rb +20 -0
- data/lib/xml_sig/signed_info.rb +27 -0
- data/lib/xml_sig/transform.rb +37 -0
- data/lib/xml_sig.rb +11 -0
- data/scashin133-rsaml.gemspec +180 -0
- data/test/action_namespace_test.rb +93 -0
- data/test/action_test.rb +51 -0
- data/test/advice_test.rb +25 -0
- data/test/assertion_test.rb +192 -0
- data/test/attribute_test.rb +60 -0
- data/test/authentication_context_test.rb +26 -0
- data/test/conditions_test.rb +84 -0
- data/test/evidence_test.rb +33 -0
- data/test/identifier_test.rb +22 -0
- data/test/issuer_test.rb +32 -0
- data/test/name_test.rb +32 -0
- data/test/parser_test.rb +32 -0
- data/test/protocol/assertion_id_request_test.rb +19 -0
- data/test/protocol/attribute_query_test.rb +30 -0
- data/test/protocol/authn_query_test.rb +20 -0
- data/test/protocol/authn_request_test.rb +56 -0
- data/test/protocol/authz_decision_query_test.rb +31 -0
- data/test/protocol/idp_list_test.rb +15 -0
- data/test/protocol/request_test.rb +66 -0
- data/test/protocol/response_test.rb +68 -0
- data/test/protocol/scoping_test.rb +20 -0
- data/test/protocol/status_code_test.rb +34 -0
- data/test/protocol/status_test.rb +16 -0
- data/test/proxy_restriction_test.rb +20 -0
- data/test/rsaml_test.rb +12 -0
- data/test/sample_data/attribute_query.xml +8 -0
- data/test/statement_test.rb +101 -0
- data/test/subject_locality_test.rb +27 -0
- data/test/subject_test.rb +44 -0
- data/test/test_helper.rb +16 -0
- data/test/xml_sig/canonicalization_test.rb +19 -0
- data/test/xml_sig/iso-8859-1.txt +1 -0
- metadata +206 -0
@@ -0,0 +1,10 @@
|
|
1
|
+
module RSAML #:nodoc
|
2
|
+
# Module that contain SAML statements.
|
3
|
+
module Statement
|
4
|
+
end
|
5
|
+
end
|
6
|
+
|
7
|
+
require 'rsaml/statement/base'
|
8
|
+
require 'rsaml/statement/authentication_statement'
|
9
|
+
require 'rsaml/statement/attribute_statement'
|
10
|
+
require 'rsaml/statement/authorization_decision_statement'
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module RSAML #:nodoc:
|
2
|
+
# Specifies the principal that is the subject of all of the (zero or more)
|
3
|
+
# statements in an assertion.
|
4
|
+
class Subject
|
5
|
+
|
6
|
+
# The subject identifier
|
7
|
+
attr_accessor :identifier
|
8
|
+
|
9
|
+
# Initialize the subject with the given identifier
|
10
|
+
def initialize(identifier=nil)
|
11
|
+
@identifier = identifier
|
12
|
+
end
|
13
|
+
|
14
|
+
# Information that allows the subject to be confirmed. If more than one subject confirmation is provided,
|
15
|
+
# then satisfying any one of them is sufficient to confirm the subject for the purpose of applying the
|
16
|
+
# assertion.
|
17
|
+
def subject_confirmations
|
18
|
+
@subject_confirmations ||= []
|
19
|
+
end
|
20
|
+
|
21
|
+
# Construct an XML fragment representing the subject
|
22
|
+
def to_xml(xml=Builder::XmlMarkup.new)
|
23
|
+
xml.tag!('saml:Subject') {
|
24
|
+
xml << identifier.to_xml unless identifier.nil?
|
25
|
+
xml << subject_confirmations.map { |sc| sc.to_xml }.join
|
26
|
+
}
|
27
|
+
end
|
28
|
+
|
29
|
+
# Construct a Subject from an XML Element.
|
30
|
+
def self.from_xml(element)
|
31
|
+
element = REXML::Document.new(element).root if element.is_a?(String)
|
32
|
+
element.get_elements('saml:NameID').each do |identifier|
|
33
|
+
return Subject.new(Identifier::Name.from_xml(identifier))
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module RSAML #:nodoc:
|
2
|
+
# Provides the means for a relying party to verify the correspondence of the subject of the
|
3
|
+
# assertion with the party with whom the relying party is communicating.
|
4
|
+
class SubjectConfirmation
|
5
|
+
|
6
|
+
# Hash of available SAML methods for subject confirmation
|
7
|
+
def self.methods
|
8
|
+
{
|
9
|
+
:holder_of_key => 'urn:oasis:names:tc:SAML:2.0:cm:holder-of-key',
|
10
|
+
:sender_vouches => 'urn:oasis:names:tc:SAML:2.0:cm:sender-vouches',
|
11
|
+
:bearer => 'urn:oasis:names:tc:SAML:2.0:cm:bearer'
|
12
|
+
}
|
13
|
+
end
|
14
|
+
|
15
|
+
# A URI reference that identifies a protocol or mechanism to be used to confirm the subject.
|
16
|
+
attr_accessor :method
|
17
|
+
|
18
|
+
# Identifies the entity expected to satisfy the enclosing subject confirmation requirements.
|
19
|
+
attr_accessor :identifier
|
20
|
+
|
21
|
+
# Additional confirmation information to be used by a specific confirmation method.
|
22
|
+
attr_accessor :subject_confirmation_data
|
23
|
+
|
24
|
+
def initialize(method)
|
25
|
+
@method = method
|
26
|
+
end
|
27
|
+
|
28
|
+
# Construct an XML fragment representing the subject confirmation
|
29
|
+
def to_xml(xml=Builder::XmlMarkup.new)
|
30
|
+
attributes = {'Method' => method}
|
31
|
+
xml.tag!('saml:SubjectConfirmation', attributes)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module RSAML #:nodoc:
|
2
|
+
# specifies additional data that allows the subject to be confirmed or constrains the circumstances under
|
3
|
+
# which the act of subject confirmation can take place. Subject confirmation takes place when a relying
|
4
|
+
# party seeks to verify the relationship between an entity presenting the assertion (that is, the attesting
|
5
|
+
# entity) and the subject of the assertion's claims.
|
6
|
+
class SubjectConfirmationData
|
7
|
+
# A time instant before which the subject cannot be confirmed. The time value is encoded in UTC.
|
8
|
+
attr_accessor :not_before
|
9
|
+
|
10
|
+
# A time instant at which the subject can no longer be confirmed. The time value is encoded in UTC.
|
11
|
+
attr_accessor :not_on_or_after
|
12
|
+
|
13
|
+
# A URI specifying the entity or location to which an attesting entity can present the assertion. For
|
14
|
+
# example, this attribute might indicate that the assertion must be delivered to a particular network
|
15
|
+
# endpoint in order to prevent an intermediary from redirecting it someplace else.
|
16
|
+
attr_accessor :recipient
|
17
|
+
|
18
|
+
# The ID of a SAML protocol message in response to which an attesting entity can present the
|
19
|
+
# assertion. For example, this attribute might be used to correlate the assertion to a SAML request that
|
20
|
+
# resulted in its presentation.
|
21
|
+
attr_accessor :in_response_to
|
22
|
+
|
23
|
+
# The network address/location from which an attesting entity can present the assertion. For example,
|
24
|
+
# this attribute might be used to bind the assertion to particular client addresses to prevent an attacker
|
25
|
+
# from easily stealing and presenting the assertion from another location.
|
26
|
+
attr_accessor :address
|
27
|
+
|
28
|
+
# Point for extension attributes
|
29
|
+
def attributes
|
30
|
+
@attributes = []
|
31
|
+
end
|
32
|
+
|
33
|
+
# Point for extension elements
|
34
|
+
def elements
|
35
|
+
@elements = []
|
36
|
+
end
|
37
|
+
|
38
|
+
# Confirm the subject confirmation data
|
39
|
+
def confirm
|
40
|
+
raise ConfirmationError, "Subject confirmation failed: not before" if not_before && Time.now < not_before
|
41
|
+
raise ConfirmationError, "Subject confirmation failed: not on or after" if not_on_or_after && Time.now >= not_on_or_after
|
42
|
+
# TODO implement tests for remaining elements such as recipient, in_response_to and address
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module RSAML #:nodoc:
|
2
|
+
# This element is entirely advisory, since both of these fields are quite easily "spoofed,"
|
3
|
+
# but may be useful information in some applications.
|
4
|
+
class SubjectLocality
|
5
|
+
# The network address of the system from which the principal identified by the subject was
|
6
|
+
# authenticated.
|
7
|
+
attr_accessor :address
|
8
|
+
|
9
|
+
# The DNS name of the system from which the principal identified by the subject was authenticated.
|
10
|
+
attr_accessor :dns_name
|
11
|
+
|
12
|
+
# Raise an error if the subject locality is structurally invalid.
|
13
|
+
def validate
|
14
|
+
unless address =~ /^(\d{1,3}\.){3}\d{1,3}$/
|
15
|
+
raise ValidationError, "Invalid address"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
# Construct an XML fragment representing the subject locality
|
20
|
+
def to_xml(xml=Builder::XmlMarkup.new)
|
21
|
+
attributes = {}
|
22
|
+
attributes['Address'] = address unless address.nil?
|
23
|
+
attributes['DNSName'] = dns_name unless dns_name.nil?
|
24
|
+
xml.tag!('saml:SubjectLocality', attributes)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module RSAML
|
2
|
+
# Module that can be mixed in to any class to provide a :valid? method. This method
|
3
|
+
# will look for a :validate method and invoke it, catching any ValidationError exceptions
|
4
|
+
# and return either true if the SAML object is structurally valid or false if it isn't.
|
5
|
+
module Validatable
|
6
|
+
attr_accessor :verbose
|
7
|
+
# Return true if the object is valid. Only objects with a validate method will
|
8
|
+
# be checked for validity.
|
9
|
+
def valid?
|
10
|
+
if respond_to?(:validate)
|
11
|
+
begin
|
12
|
+
validate
|
13
|
+
rescue ValidationError => e
|
14
|
+
puts "Validation failed: #{e.message}" if verbose
|
15
|
+
return false
|
16
|
+
end
|
17
|
+
end
|
18
|
+
return true
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
data/lib/rsaml.rb
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
$KCODE = 'UTF-8'
|
2
|
+
|
3
|
+
module RSAML
|
4
|
+
def saml_namespaces
|
5
|
+
{
|
6
|
+
'saml' => 'urn:oasis:names:tc:SAML:2.0:assertion',
|
7
|
+
'samlp' => 'urn:oasis:names:tc:SAML:2.0:protocol',
|
8
|
+
'ds' => 'http://www.w3.org/2000/09/xmldsig#',
|
9
|
+
'xenc' => 'http://www.w3.org/2001/04/xmlenc#',
|
10
|
+
'xs' => 'http://www.w3.org/2001/XMLSchema',
|
11
|
+
'xsi' => 'http://www.w3.org/2001/XMLSchema-instance'
|
12
|
+
}
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
require 'rubygems'
|
17
|
+
require 'uuid'
|
18
|
+
require 'activesupport'
|
19
|
+
|
20
|
+
$:.unshift(File.dirname(__FILE__))
|
21
|
+
|
22
|
+
require 'xml_sig'
|
23
|
+
require 'xml_enc'
|
24
|
+
|
25
|
+
require 'rsaml/ext/string'
|
26
|
+
|
27
|
+
require 'rsaml/encrypted'
|
28
|
+
require 'rsaml/validatable'
|
29
|
+
require 'rsaml/errors'
|
30
|
+
|
31
|
+
require 'rsaml/action'
|
32
|
+
require 'rsaml/action_namespace'
|
33
|
+
require 'rsaml/advice'
|
34
|
+
require 'rsaml/assertion'
|
35
|
+
require 'rsaml/attribute'
|
36
|
+
require 'rsaml/audience'
|
37
|
+
require 'rsaml/authentication_context'
|
38
|
+
require 'rsaml/condition'
|
39
|
+
require 'rsaml/conditions'
|
40
|
+
require 'rsaml/evidence'
|
41
|
+
require 'rsaml/identifier'
|
42
|
+
require 'rsaml/proxy_restriction'
|
43
|
+
require 'rsaml/statement'
|
44
|
+
require 'rsaml/subject'
|
45
|
+
require 'rsaml/subject_confirmation'
|
46
|
+
require 'rsaml/subject_confirmation_data'
|
47
|
+
require 'rsaml/subject_locality'
|
48
|
+
|
49
|
+
require 'rsaml/protocol'
|
50
|
+
|
51
|
+
require 'rsaml/parser'
|
data/lib/xml_enc.rb
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'iconv'
|
2
|
+
|
3
|
+
module XmlSig #:nodoc:
|
4
|
+
class CanonicalizationMethod
|
5
|
+
attr_accessor :algorithm
|
6
|
+
|
7
|
+
def validate
|
8
|
+
raise ValidationError, "Algorithm is required" if algorithm.nil?
|
9
|
+
end
|
10
|
+
|
11
|
+
def to_xml(xml=Builder::XmlMarkup.new)
|
12
|
+
attributes = {'Algorightm' => algorithm}
|
13
|
+
xml.tag!('ds:CanonicalizationMethod', attributes)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class XMLC14NBase
|
18
|
+
# Convert the content from the given charset to UTF-8.
|
19
|
+
def convert_to_utf8(content, from)
|
20
|
+
Iconv.iconv('UTF-8', from, content).join
|
21
|
+
end
|
22
|
+
def convert_linebreaks(content)
|
23
|
+
content.gsub(/\r\n/, "\n").gsub(/\r/, "\n")
|
24
|
+
end
|
25
|
+
def normalize_attribute_values(content)
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# Canonicalization algorithm for XML removing comments
|
31
|
+
class XMLC14NWithComments < XMLC14NBase
|
32
|
+
def process(content, charset='UTF-8')
|
33
|
+
content = convert_to_utf8(content) unless charset == 'UTF-8'
|
34
|
+
content
|
35
|
+
end
|
36
|
+
end
|
37
|
+
class XMLC14NWithoutComments < XMLC14NBase
|
38
|
+
def process(content, charset='UTF-8')
|
39
|
+
content = convert_to_utf8(content) unless charset == 'UTF-8'
|
40
|
+
doc = REXML::Document.new(content)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module XmlSig #:nodoc:
|
2
|
+
class KeyInfo
|
3
|
+
attr_accessor :id
|
4
|
+
attr_accessor :key_name
|
5
|
+
attr_accessor :key_value
|
6
|
+
attr_accessor :retrieval_method
|
7
|
+
attr_accessor :key_data
|
8
|
+
|
9
|
+
def to_xml(xml=Builder::XmlMarkup.new)
|
10
|
+
xml.tag!('ds:KeyInfo') {
|
11
|
+
xml.tag!('ds:KeyName', key_name)
|
12
|
+
xml.tag!('ds:KeyValue') {
|
13
|
+
xml << key_value.to_xml
|
14
|
+
}
|
15
|
+
}
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
class RetrievalMethod
|
20
|
+
attr_accessor :uri
|
21
|
+
attr_accessor :type
|
22
|
+
|
23
|
+
def transforms
|
24
|
+
@transforms ||= []
|
25
|
+
end
|
26
|
+
|
27
|
+
def validate
|
28
|
+
raise ValidationError, "URI is required" if uri.nil?
|
29
|
+
end
|
30
|
+
|
31
|
+
def to_xml(xml=Builder::XmlMarkup.new)
|
32
|
+
attributes = {'URI' => uri}
|
33
|
+
attributes['Type'] = type unless type.nil?
|
34
|
+
xml.tag!('ds:RetrievalMethod', attributes) {
|
35
|
+
transforms.each { |transform| xml << transform.to_xml }
|
36
|
+
}
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# REQUIRED
|
41
|
+
class DSAKeyValue
|
42
|
+
end
|
43
|
+
# OPTIONAL
|
44
|
+
class RSAKeyValue
|
45
|
+
end
|
46
|
+
|
47
|
+
class X509Data
|
48
|
+
end
|
49
|
+
class PGPData
|
50
|
+
end
|
51
|
+
class SPKIData
|
52
|
+
end
|
53
|
+
class MgmtData
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module XmlSig #:nooc:
|
2
|
+
class Reference
|
3
|
+
attr_accessor :id
|
4
|
+
attr_accessor :uri
|
5
|
+
attr_accessor :type
|
6
|
+
|
7
|
+
attr_accessor :digest_method
|
8
|
+
|
9
|
+
# DigestValue is an element that contains the encoded value of the digest. The
|
10
|
+
# digest is always encoded using base64
|
11
|
+
attr_accessor :digest_value
|
12
|
+
|
13
|
+
def transforms
|
14
|
+
@transforms ||= []
|
15
|
+
end
|
16
|
+
|
17
|
+
def validate
|
18
|
+
raise ValidationError, "Digest method is required" if digest_method.nil?
|
19
|
+
raise ValidationError, "Digest value is required" if digest_value.nil?
|
20
|
+
end
|
21
|
+
|
22
|
+
def to_xml(xml=Builder::XmlMarkup.new)
|
23
|
+
attributes = {}
|
24
|
+
attributes['Id'] = id unless id.nil?
|
25
|
+
attributes['URI'] = uri unless uri.nil?
|
26
|
+
attributes['Type'] = type unless type.nil?
|
27
|
+
xml.tag!('ds:Reference', attributes) {
|
28
|
+
xml.tag!('ds:Transforms') {
|
29
|
+
transforms.each { |transform| xml << transform.to_xml }
|
30
|
+
}
|
31
|
+
xml << digest_method.to_xml unless digest_method.nil?
|
32
|
+
xml.tag!('ds:DigestValue', digest_value)
|
33
|
+
}
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# DigestMethod is a required element that identifies the digest algorithm to be applied
|
38
|
+
# to the signed object.
|
39
|
+
class DigestMethod
|
40
|
+
def self.identifiers
|
41
|
+
@identifiers ||= {
|
42
|
+
'SHA-1', 'http://www.w3.org/2000/09/xmldsig#sha1'
|
43
|
+
}
|
44
|
+
end
|
45
|
+
|
46
|
+
attr_accessor :algorithm
|
47
|
+
|
48
|
+
def validate
|
49
|
+
raise ValidationError, "Algorithm is required" if algorithm.nil?
|
50
|
+
end
|
51
|
+
|
52
|
+
def to_xml(xml=Builder::XmlMarkup.new)
|
53
|
+
attributes = {'Algorightm' => algorithm}
|
54
|
+
xml.tag!('ds:DigestMethod', attributes)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module XmlSig #:nodoc:
|
2
|
+
# An XML signature.
|
3
|
+
class Signature
|
4
|
+
attr_accessor :id
|
5
|
+
attr_accessor :signed_info
|
6
|
+
attr_accessor :signature_value
|
7
|
+
attr_accessor :key_info
|
8
|
+
|
9
|
+
def objects
|
10
|
+
@objects ||= []
|
11
|
+
end
|
12
|
+
|
13
|
+
def assert
|
14
|
+
# raise AssertionError, "An assertion signature must be valid"
|
15
|
+
end
|
16
|
+
|
17
|
+
# Construct an XML fragment representing the signature
|
18
|
+
def to_xml(xml=Builder::XmlMarkup.new)
|
19
|
+
attributes = {}
|
20
|
+
attributes['Id'] = id unless id.nil?
|
21
|
+
attributes['xmlns:ds'] = "http://www.w3.org/2000/09/xmldsig#"
|
22
|
+
xml.tag!('ds:Signature', attributes) {
|
23
|
+
xml << signed_info.to_xml if signed_info
|
24
|
+
xml.tag!('ds:SignatureValue')
|
25
|
+
xml.tag!('ds:KeyInfo') if key_info
|
26
|
+
}
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module XmlSig #:nodoc:
|
2
|
+
# SignatureMethod is a required element that specifies the algorithm used for
|
3
|
+
# signature generation and validation. This algorithm identifies all cryptographic
|
4
|
+
# functions involved in the signature operation (e.g. hashing, public key
|
5
|
+
# algorithms, MACs, padding, etc.).
|
6
|
+
class SignatureMethod
|
7
|
+
attr_accessor :algorithm
|
8
|
+
|
9
|
+
def validate
|
10
|
+
raise ValidationError, "Algorithm is required" if algorithm.nil?
|
11
|
+
end
|
12
|
+
|
13
|
+
def to_xml(xml=Builder::XmlMarkup.new)
|
14
|
+
attributes = {'Algorightm' => algorithm}
|
15
|
+
xml.tag!('ds:SignatureMethod', attributes) {
|
16
|
+
xml.tag!('ds:HMACOutputLength', hmac_output_length) unless hmac_output_length.nil?
|
17
|
+
}
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module XmlSig #:nodoc:
|
2
|
+
class SignedInfo
|
3
|
+
attr_accessor :id
|
4
|
+
attr_accessor :canonicalization_method
|
5
|
+
attr_accessor :signature_method
|
6
|
+
|
7
|
+
def references
|
8
|
+
@references ||= []
|
9
|
+
end
|
10
|
+
|
11
|
+
def validate
|
12
|
+
raise ValidationError, "Canonicalization method is required" if canonicalization_method.nil?
|
13
|
+
raise ValidationError, "Signature method is required" if signature_method.nil?
|
14
|
+
raise ValidationError, "At least one reference is required" if references.empty?
|
15
|
+
end
|
16
|
+
|
17
|
+
def to_xml(xml=Builder::XmlMarkup.new)
|
18
|
+
attributes = {}
|
19
|
+
attributes['Id'] = id unless id.nil?
|
20
|
+
xml.tag!('ds:SignedInfo', attributes) {
|
21
|
+
xml << canonicalization_method.to_xml unless canonicalization_method.nil?
|
22
|
+
xml << signature_method.to_xml unless signature_method.nil?
|
23
|
+
references.each { |reference| xml << reference.to_xml }
|
24
|
+
}
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module XmlSig #:nodoc:
|
2
|
+
class Transform
|
3
|
+
attr_accessor :algorithm
|
4
|
+
attr_accessor :xpath
|
5
|
+
|
6
|
+
def to_xml(xml=Builder::XmlMarkup.new)
|
7
|
+
attributes = {'Algorightm' => algorithm}
|
8
|
+
xml.tag!('ds:Transform', attributes) {
|
9
|
+
xml.tag!('ds:XPath', xpath) unless xpath.nil?
|
10
|
+
}
|
11
|
+
end
|
12
|
+
end
|
13
|
+
class Base64Transform
|
14
|
+
IDENTIFIER = 'http://www.w3.org/2000/09/xmldsig#base64'
|
15
|
+
def process(content)
|
16
|
+
content # TODO: implement
|
17
|
+
end
|
18
|
+
end
|
19
|
+
class XPathFiltering
|
20
|
+
IDENTIFIER = 'http://www.w3.org/TR/1999/REC-xpath-19991116'
|
21
|
+
def process(content)
|
22
|
+
content # TODO: implement
|
23
|
+
end
|
24
|
+
end
|
25
|
+
class EnvelopedSignatureTransform
|
26
|
+
IDENTIFIER = 'http://www.w3.org/2000/09/xmldsig#enveloped-signature'
|
27
|
+
def process(content)
|
28
|
+
content # TODO: implement
|
29
|
+
end
|
30
|
+
end
|
31
|
+
class XSLTTransform
|
32
|
+
IDENTIFIER = 'http://www.w3.org/TR/1999/REC-xslt-19991116'
|
33
|
+
def process(content)
|
34
|
+
content # TODO: implement
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
data/lib/xml_sig.rb
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
# Ruby XML Signature implementation
|
2
|
+
module XmlSig
|
3
|
+
end
|
4
|
+
|
5
|
+
require 'xml_sig/signature'
|
6
|
+
require 'xml_sig/signature_method'
|
7
|
+
require 'xml_sig/canonicalization_method'
|
8
|
+
require 'xml_sig/reference'
|
9
|
+
require 'xml_sig/signed_info'
|
10
|
+
require 'xml_sig/key_info'
|
11
|
+
require 'xml_sig/transform'
|