saml2 1.0.3 → 1.0.4

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 90af41e6460d5aa014d4b54d4e597868d005e26b
4
- data.tar.gz: 00833d534d9a8e97c08a78d52becb64b70b82aab
3
+ metadata.gz: a3df3b121cbc505cf89bd09bf2551c4bf169522e
4
+ data.tar.gz: bee5074779df61a8d6decfc85b1137f407f3bafb
5
5
  SHA512:
6
- metadata.gz: 88afb82849c17a10a3b2d0bb580cec358bc2cbdbb26ddb4b0c16d0d236aca871be81b514c6b86b6cb35163fa91b44a13e011df7f1c16d902371ce88657463406
7
- data.tar.gz: 2f7b4cb6fef7079a6dca04a8051e0f7921199962d50ab24123d439e8fa179dcb5903875173f6b791d3c13fb7268d237b323682a4017f6d43491fd2b6e8b387bf
6
+ metadata.gz: f960b992502f20a9a518b53a34e7c50d5d3fae14452d51704f1eb36308accf5f3a48e3f5810d35a31bb3a64cb605ba2a5a49a18e6d01d8f36037a467ab36bf0a
7
+ data.tar.gz: 050953212fed3515aa2a329b24e1adcf1fc7f57bed49d86e700db5d0e47bae8f6c6cc346e1cb02bae366302bcb5c1ce414e32fc7d97adb6b1ad49ee7205a9a3f
@@ -1,23 +1,10 @@
1
+ require 'date'
2
+
1
3
  require 'saml2/base'
2
4
  require 'saml2/namespaces'
3
5
 
4
6
  module SAML2
5
- class AttributeType < Base
6
- attr_accessor :name, :friendly_name, :name_format
7
-
8
- def initialize(name = nil, friendly_name = nil, name_format = nil)
9
- @name, @friendly_name, @name_format = name, friendly_name, name_format
10
- end
11
-
12
- def from_xml(node)
13
- @name = node['Name']
14
- @friendly_name = node['FriendlyName']
15
- @name_format = node['NameFormat']
16
- self
17
- end
18
- end
19
-
20
- class Attribute < AttributeType
7
+ class Attribute < Base
21
8
  module NameFormats
22
9
  BASIC = "urn:oasis:names:tc:SAML:2.0:attrname-format:basic".freeze
23
10
  UNSPECIFIED = "urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified".freeze
@@ -38,25 +25,28 @@ module SAML2
38
25
  super unless self == Attribute
39
26
 
40
27
  # look for an appropriate subclass
41
- klass = subclasses.find { |klass| klass.recognizes?(node) }
42
- if klass
43
- klass.from_xml(node)
44
- else
45
- super
46
- end
28
+ klass = class_for(node)
29
+ klass ? klass.from_xml(node) : super
47
30
  end
48
31
 
49
32
  def create(name, value = nil)
50
- klass = subclasses.find { |klass| klass.recognizes?(name) } || self
51
- klass.new(name, value)
33
+
34
+ (class_for(name) || self).new(name, value)
35
+ end
36
+
37
+ protected
38
+
39
+ def class_for(name_or_node)
40
+ subclasses.find do |klass|
41
+ klass.respond_to?(:recognizes?) && klass.recognizes?(name_or_node)
42
+ end
52
43
  end
53
44
  end
54
45
 
55
- attr_accessor :value
46
+ attr_accessor :name, :friendly_name, :name_format, :value
56
47
 
57
48
  def initialize(name = nil, value = nil, friendly_name = nil, name_format = nil)
58
- super(name, friendly_name, name_format)
59
- @value = value
49
+ @name, @value, @friendly_name, @name_format = name, value, friendly_name, name_format
60
50
  end
61
51
 
62
52
  def build(builder)
@@ -73,10 +63,17 @@ module SAML2
73
63
  end
74
64
 
75
65
  def from_xml(node)
76
- @value = node.xpath('saml:AttributeValue', Namespaces::ALL).map do |node|
66
+ @name = node['Name']
67
+ @friendly_name = node['FriendlyName']
68
+ @name_format = node['NameFormat']
69
+ values = node.xpath('saml:AttributeValue', Namespaces::ALL).map do |node|
77
70
  convert_from_xsi(node['xsi:type'], node.content && node.content.strip)
78
71
  end
79
- @value = @value.first if @value.length == 1
72
+ @value = case values.length
73
+ when 0; nil
74
+ when 1; values.first
75
+ else; values
76
+ end
80
77
  super
81
78
  end
82
79
 
@@ -3,9 +3,9 @@ require 'saml2/indexed_object'
3
3
  require 'saml2/namespaces'
4
4
 
5
5
  module SAML2
6
- class RequestedAttribute < AttributeType
6
+ class RequestedAttribute < Attribute
7
7
  def initialize(name = nil, is_required = nil, name_format = nil)
8
- super(name, name_format)
8
+ super(name, nil, nil, name_format)
9
9
  @is_required = is_required
10
10
  end
11
11
 
@@ -28,6 +28,17 @@ module SAML2
28
28
  end
29
29
  end
30
30
 
31
+ class InvalidAttributeValue < RuntimeError
32
+ attr_reader :requested_attribute, :provided_value
33
+
34
+ def initialize(requested_attribute, provided_value)
35
+ super("Attribute #{requested_attribute.name} is provided value " \
36
+ "#{provided_value.inspect}, but only allows " \
37
+ "#{Array(requested_attribute.value).inspect}")
38
+ @requested_attribute, @provided_value = requested_attribute, provided_value
39
+ end
40
+ end
41
+
31
42
  class AttributeConsumingService < Base
32
43
  include IndexedObject
33
44
 
@@ -64,9 +75,20 @@ module SAML2
64
75
  attr ||= attributes_hash[[requested_attr.name, nil]]
65
76
  end
66
77
  if attr
78
+ if requested_attr.value &&
79
+ !Array(requested_attr.value).include?(attr.value)
80
+ raise InvalidAttributeValue.new(requested_attr, attr.value)
81
+ end
67
82
  attributes << attr
68
83
  elsif requested_attr.required?
69
- raise RequiredAttributeMissing.new(requested_attr)
84
+ # if the metadata includes only one possible value, helpfully set
85
+ # that value
86
+ if requested_attr.value && !requested_attr.value.is_a?(::Array)
87
+ attributes << Attribute.create(requested_attr.name,
88
+ requested_attr.value)
89
+ else
90
+ raise RequiredAttributeMissing.new(requested_attr)
91
+ end
70
92
  end
71
93
  end
72
94
  return nil if attributes.empty?
@@ -1,3 +1,3 @@
1
1
  module SAML2
2
- VERSION = '1.0.3'
2
+ VERSION = '1.0.4'
3
3
  end
@@ -69,6 +69,59 @@ module SAML2
69
69
  stmt.attributes.first.name.must_equal 'name'
70
70
  stmt.attributes.first.value.must_equal 'cody'
71
71
  end
72
+
73
+ it "requires that provided attributes match a single default" do
74
+ acs.requested_attributes.clear
75
+ attr = RequestedAttribute.new('attr')
76
+ attr.value = 'value'
77
+ acs.requested_attributes << attr
78
+ -> { acs.create_statement('attr' => 'something') }.must_raise InvalidAttributeValue
79
+ stmt = acs.create_statement('attr' => 'value')
80
+ stmt.attributes.length.must_equal 1
81
+ stmt.attributes.first.name.must_equal 'attr'
82
+ stmt.attributes.first.value.must_equal 'value'
83
+ end
84
+
85
+ it "requires that provided attributes be from allowed enumeration" do
86
+ acs.requested_attributes.clear
87
+ attr = RequestedAttribute.new('attr')
88
+ attr.value = ['value1', 'value2']
89
+ acs.requested_attributes << attr
90
+ -> { acs.create_statement('attr' => 'something') }.must_raise InvalidAttributeValue
91
+ stmt = acs.create_statement('attr' => 'value1')
92
+ stmt.attributes.length.must_equal 1
93
+ stmt.attributes.first.name.must_equal 'attr'
94
+ stmt.attributes.first.value.must_equal 'value1'
95
+ end
96
+
97
+ it "auto-provides missing required attribute with a default" do
98
+ acs.requested_attributes.clear
99
+ attr = RequestedAttribute.new('attr', true)
100
+ attr.value = 'value'
101
+ acs.requested_attributes << attr
102
+ stmt = acs.create_statement({})
103
+ stmt.attributes.length.must_equal 1
104
+ stmt.attributes.first.name.must_equal 'attr'
105
+ stmt.attributes.first.value.must_equal 'value'
106
+ end
107
+
108
+ it "doesn't auto-provide missing required attribute with an enumeration" do
109
+ acs.requested_attributes.clear
110
+ attr = RequestedAttribute.new('attr', true)
111
+ attr.value = ['value1', 'value2']
112
+ acs.requested_attributes << attr
113
+ -> { acs.create_statement({}) }.must_raise RequiredAttributeMissing
114
+ end
115
+
116
+ it "doesn't auto-provide missing non-required attribute with a default" do
117
+ acs.requested_attributes.clear
118
+ attr = RequestedAttribute.new('attr')
119
+ attr.value = 'value'
120
+ acs.requested_attributes << attr
121
+ stmt = acs.create_statement({})
122
+ stmt.must_equal nil
123
+ end
124
+
72
125
  end
73
126
  end
74
127
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: saml2
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.3
4
+ version: 1.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Cody Cutrer
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-03-25 00:00:00.000000000 Z
11
+ date: 2015-05-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: nokogiri