shaf 1.6.1 → 2.0.0

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 (155) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/iana_link_relations.csv.gz +0 -0
  5. data/lib/shaf.rb +6 -0
  6. data/lib/shaf/alps/attribute_serializer.rb +41 -0
  7. data/lib/shaf/alps/json_serializer.rb +50 -0
  8. data/lib/shaf/alps/relation_serializer.rb +70 -0
  9. data/lib/shaf/api_doc/link_relations.rb +77 -0
  10. data/lib/shaf/authenticator.rb +56 -0
  11. data/lib/shaf/authenticator/base.rb +161 -0
  12. data/lib/shaf/authenticator/basic_auth.rb +25 -0
  13. data/lib/shaf/authenticator/challenge.rb +32 -0
  14. data/lib/shaf/authenticator/parameter.rb +31 -0
  15. data/lib/shaf/authenticator/request.rb +17 -0
  16. data/lib/shaf/command/console.rb +1 -1
  17. data/lib/shaf/command/generate.rb +5 -2
  18. data/lib/shaf/command/new.rb +20 -7
  19. data/lib/shaf/command/templates/Gemfile.erb +1 -0
  20. data/{templates/config/settings.yml → lib/shaf/command/templates/config/settings.yml.erb} +1 -5
  21. data/lib/shaf/errors.rb +11 -0
  22. data/lib/shaf/extensions.rb +3 -3
  23. data/lib/shaf/extensions/api_routes.rb +60 -0
  24. data/lib/shaf/extensions/authorize.rb +11 -9
  25. data/lib/shaf/extensions/log.rb +1 -1
  26. data/lib/shaf/extensions/resource_uris.rb +139 -63
  27. data/lib/shaf/extensions/symbolic_routes.rb +22 -19
  28. data/lib/shaf/formable.rb +1 -2
  29. data/lib/shaf/formable/form.rb +1 -1
  30. data/lib/shaf/generator.rb +2 -0
  31. data/lib/shaf/generator/base.rb +2 -3
  32. data/lib/shaf/generator/controller.rb +11 -7
  33. data/lib/shaf/generator/doc.rb +17 -0
  34. data/lib/shaf/generator/forms.rb +1 -0
  35. data/lib/shaf/generator/helper.rb +2 -1
  36. data/lib/shaf/generator/migration/base.rb +7 -3
  37. data/lib/shaf/generator/migration/type.rb +4 -26
  38. data/lib/shaf/generator/migration/types.rb +45 -16
  39. data/lib/shaf/generator/model.rb +1 -2
  40. data/lib/shaf/generator/profile.rb +52 -0
  41. data/lib/shaf/generator/serializer.rb +38 -73
  42. data/lib/shaf/generator/templates/api/policy.rb.erb +2 -2
  43. data/lib/shaf/generator/templates/api/profile.rb.erb +16 -0
  44. data/lib/shaf/generator/templates/api/serializer.rb.erb +2 -2
  45. data/lib/shaf/generator/templates/spec/integration_spec.rb.erb +1 -2
  46. data/lib/shaf/generator/templates/spec/serializer_spec.rb.erb +5 -5
  47. data/lib/shaf/helpers.rb +4 -0
  48. data/lib/shaf/helpers/authentication.rb +79 -0
  49. data/lib/shaf/helpers/payload.rb +14 -34
  50. data/lib/shaf/helpers/vary.rb +8 -0
  51. data/lib/shaf/logger.rb +12 -0
  52. data/lib/shaf/parser.rb +65 -0
  53. data/lib/shaf/parser/base.rb +44 -0
  54. data/lib/shaf/parser/form_data.rb +15 -0
  55. data/lib/shaf/parser/json.rb +26 -0
  56. data/lib/shaf/profile.rb +110 -0
  57. data/lib/shaf/profile/attribute.rb +29 -0
  58. data/lib/shaf/profile/evaluator.rb +46 -0
  59. data/lib/shaf/profile/relation.rb +29 -0
  60. data/lib/shaf/profile/unique_id.rb +58 -0
  61. data/lib/shaf/profiles.rb +42 -0
  62. data/lib/shaf/profiles/shaf_basic.rb +20 -0
  63. data/lib/shaf/profiles/shaf_error.rb +48 -0
  64. data/lib/shaf/profiles/shaf_form.rb +109 -0
  65. data/lib/shaf/responder.rb +41 -2
  66. data/lib/shaf/responder/alps_json.rb +25 -0
  67. data/lib/shaf/responder/base.rb +20 -17
  68. data/lib/shaf/responder/hal.rb +65 -4
  69. data/lib/shaf/responder/html.rb +43 -16
  70. data/lib/shaf/responder/problem_json.rb +1 -1
  71. data/lib/shaf/serializer.rb +31 -0
  72. data/lib/shaf/settings.rb +25 -12
  73. data/lib/shaf/spec.rb +1 -0
  74. data/lib/shaf/spec/authenticator.rb +13 -0
  75. data/lib/shaf/spec/base.rb +1 -1
  76. data/lib/shaf/spec/http_method_utils.rb +1 -1
  77. data/lib/shaf/spec/integration_spec.rb +25 -13
  78. data/lib/shaf/spec/payload_utils.rb +2 -2
  79. data/lib/shaf/supported_http_methods.rb +15 -0
  80. data/lib/shaf/tasks/api_doc_task.rb +24 -3
  81. data/lib/shaf/tasks/routes_task.rb +14 -17
  82. data/lib/shaf/upgrade/manifest.rb +11 -2
  83. data/lib/shaf/upgrade/package.rb +73 -43
  84. data/lib/shaf/upgrade/version.rb +11 -10
  85. data/lib/shaf/utils.rb +19 -5
  86. data/lib/shaf/version.rb +3 -1
  87. data/lib/shaf/yard.rb +34 -0
  88. data/lib/shaf/yard/attribute_method_handler.rb +19 -0
  89. data/lib/shaf/yard/attribute_object.rb +30 -0
  90. data/lib/shaf/yard/base_method_handler.rb +30 -0
  91. data/lib/shaf/yard/link_method_handler.rb +39 -0
  92. data/lib/shaf/yard/link_object.rb +60 -0
  93. data/lib/shaf/yard/nested_attributes.rb +37 -0
  94. data/lib/shaf/yard/parser.rb +64 -0
  95. data/lib/shaf/yard/profile_method_handler.rb +51 -0
  96. data/lib/shaf/yard/profile_object.rb +21 -0
  97. data/lib/shaf/yard/resource_object.rb +55 -0
  98. data/lib/shaf/yard/serializer_handler.rb +27 -0
  99. data/templates/api/controllers/base_controller.rb +0 -10
  100. data/templates/api/controllers/docs_controller.rb +5 -3
  101. data/templates/api/controllers/root_controller.rb +7 -1
  102. data/templates/api/policies/base_policy.rb +2 -0
  103. data/templates/api/serializers/base_serializer.rb +1 -3
  104. data/templates/api/serializers/error_serializer.rb +1 -5
  105. data/templates/api/serializers/form_serializer.rb +1 -5
  106. data/templates/api/serializers/validation_error_serializer.rb +1 -5
  107. data/templates/config/bootstrap.rb +1 -2
  108. data/templates/config/directories.rb +52 -44
  109. data/templates/config/helpers.rb +1 -1
  110. data/templates/config/initializers.rb +52 -8
  111. data/templates/config/initializers/authentication.rb +18 -0
  112. data/templates/config/initializers/db_migrations.rb +2 -2
  113. data/templates/config/initializers/logging.rb +2 -2
  114. data/templates/spec/spec_helper.rb +2 -0
  115. data/upgrades/0.5.0.tar.gz +0 -0
  116. data/upgrades/1.0.4.tar.gz +0 -0
  117. data/upgrades/1.1.0.tar.gz +0 -0
  118. data/upgrades/2.0.0.tar.gz +0 -0
  119. data/yard_templates/api_doc/doc_index/html/body.erb +3 -0
  120. data/yard_templates/api_doc/doc_index/setup.rb +8 -0
  121. data/yard_templates/api_doc/html/css/api-doc.css +222 -0
  122. data/yard_templates/api_doc/html/favicon.ico +0 -0
  123. data/yard_templates/api_doc/html/js/switch_tab.js +17 -0
  124. data/yard_templates/api_doc/html/setup.rb +59 -0
  125. data/yard_templates/api_doc/layout/html/footer.erb +3 -0
  126. data/yard_templates/api_doc/layout/html/header.erb +7 -0
  127. data/yard_templates/api_doc/layout/html/layout.erb +13 -0
  128. data/yard_templates/api_doc/layout/setup.rb +24 -0
  129. data/yard_templates/api_doc/profile/html/attributes.erb +10 -0
  130. data/yard_templates/api_doc/profile/html/profile.erb +6 -0
  131. data/yard_templates/api_doc/profile/html/relations.erb +10 -0
  132. data/yard_templates/api_doc/profile/setup.rb +38 -0
  133. data/yard_templates/api_doc/profile_attribute/html/attribute.erb +23 -0
  134. data/yard_templates/api_doc/profile_attribute/setup.rb +21 -0
  135. data/yard_templates/api_doc/profile_relation/html/relation.erb +37 -0
  136. data/yard_templates/api_doc/profile_relation/setup.rb +41 -0
  137. data/yard_templates/api_doc/resource/html/attributes.erb +10 -0
  138. data/yard_templates/api_doc/resource/html/profile.erb +14 -0
  139. data/yard_templates/api_doc/resource/html/relations.erb +10 -0
  140. data/yard_templates/api_doc/resource/html/resource.erb +5 -0
  141. data/yard_templates/api_doc/resource/setup.rb +56 -0
  142. data/yard_templates/api_doc/resource_attribute/html/attribute.erb +23 -0
  143. data/yard_templates/api_doc/resource_attribute/setup.rb +20 -0
  144. data/yard_templates/api_doc/resource_relation/html/relation.erb +47 -0
  145. data/yard_templates/api_doc/resource_relation/setup.rb +80 -0
  146. data/yard_templates/api_doc/setup.rb +31 -0
  147. data/yard_templates/api_doc/sidebar/html/profile_list.erb +8 -0
  148. data/yard_templates/api_doc/sidebar/html/search.erb +7 -0
  149. data/yard_templates/api_doc/sidebar/html/serializer_list.erb +8 -0
  150. data/yard_templates/api_doc/sidebar/html/sidebar.erb +13 -0
  151. data/yard_templates/api_doc/sidebar/setup.rb +56 -0
  152. metadata +137 -30
  153. metadata.gz.sig +1 -3
  154. data/lib/shaf/extensions/current_user.rb +0 -48
  155. data/lib/shaf/responder/hal_serializable.rb +0 -64
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 66ee277e6ce8adc77313e5df1719e018db54392e9e46e0476d220df96767d3c5
4
- data.tar.gz: 8e233c0d3f1d39bd9757a833c2baa4b50dde0c2b54bc96902b95271ccab8d47f
3
+ metadata.gz: 87353c742213c291ee2def2d0cc55c6743ef429d52655824935eb131f43c4868
4
+ data.tar.gz: 7cec9186f28226651cbc07d0310d945bb901573e5d992cc980ff9863f36c6d09
5
5
  SHA512:
6
- metadata.gz: ddb8c2dbc1b0b00f0c9badca6fad5c6a9bc7a29684bc4070fa313945283fcb7d3272ad0e933601f524f03fb8a65fcfd81ab6337af1f30b2c33d2fdce4c47605c
7
- data.tar.gz: ff383da9a2cc2936aa28e4647835bf6910b9d401346106a2b3890ed7dcb836b43517a96c2aebc6411cda0feda39da76f41d7a25d7ad9b1912f8ee3b437c17eff
6
+ metadata.gz: 7fb1521b3f4eba94982da604cd42996f9c744bda53cb04ba22fd92af02c687be0a3c3a1c22bd02a9f1478e633ef9d05e2334f212bcdb4a4a5aacb2bd9b203e61
7
+ data.tar.gz: 05eba3ff47be63a14be932312465410186407974b523c108e3bf759ec72bc94eaed3452571f397009261a12025243c19071bc7dea8b09078e0053284a7cd5dfd
checksums.yaml.gz.sig CHANGED
Binary file
data.tar.gz.sig CHANGED
Binary file
Binary file
data/lib/shaf.rb CHANGED
@@ -1,7 +1,11 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'shaf/version'
4
+ require 'shaf/logger'
2
5
  require 'shaf/settings'
3
6
  require 'shaf/command'
4
7
  require 'shaf/app'
8
+ require 'shaf/supported_http_methods'
5
9
  require 'shaf/router'
6
10
  require 'shaf/errors'
7
11
  require 'shaf/formable'
@@ -9,3 +13,5 @@ require 'shaf/extensions'
9
13
  require 'shaf/helpers'
10
14
  require 'shaf/resource_doc'
11
15
  require 'shaf/upgrade'
16
+ require 'shaf/profiles'
17
+ require 'shaf/serializer'
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Shaf
4
+ module ALPS
5
+ class AttributeSerializer
6
+ attr_reader :attribute
7
+
8
+ def self.call(arg)
9
+ new(arg).to_hash
10
+ end
11
+
12
+ def initialize(attribute)
13
+ @attribute = attribute
14
+ end
15
+
16
+ def to_hash
17
+ {
18
+ id: attribute.id,
19
+ type: 'semantic',
20
+ }.merge(optional_properties)
21
+ end
22
+
23
+ private
24
+
25
+ def optional_properties
26
+ descriptors = serialized_descriptors
27
+ hash = {}
28
+ hash[:href] = attribute.href if attribute.href
29
+ hash[:doc] = { value: attribute.doc } if attribute.doc
30
+ hash[:name] = attribute.name.to_s if attribute.name
31
+ hash[:descriptor] = descriptors unless descriptors.empty?
32
+ hash
33
+ end
34
+
35
+ def serialized_descriptors
36
+ descriptors = attribute.attributes.map { |attr| self.class.call(attr) }
37
+ descriptors += attribute.relations.map { |rel| RelationSerializer.call(rel) }
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'shaf/alps/attribute_serializer'
4
+ require 'shaf/alps/relation_serializer'
5
+
6
+ module Shaf
7
+ module ALPS
8
+ class JsonSerializer
9
+ ALPS_VERSION = '1.0'
10
+
11
+ def self.call(profile)
12
+ new(profile).to_hash
13
+ end
14
+
15
+ attr_reader :profile
16
+
17
+ def initialize(profile)
18
+ @profile = profile
19
+ end
20
+
21
+ def to_hash
22
+ {
23
+ alps: {
24
+ version: ALPS_VERSION,
25
+ doc: profile.doc,
26
+ descriptor: descriptors,
27
+ }.compact
28
+ }
29
+ end
30
+
31
+ private
32
+
33
+ def descriptors
34
+ attribute_descriptors + relation_descriptors
35
+ end
36
+
37
+ def attribute_descriptors
38
+ profile.attributes.map do |desc|
39
+ AttributeSerializer.call(desc)
40
+ end
41
+ end
42
+
43
+ def relation_descriptors
44
+ profile.relations.map do |desc|
45
+ RelationSerializer.call(desc)
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Shaf
4
+ module ALPS
5
+ class RelationSerializer
6
+ SAFE_METHODS = ['GET', 'HEAD', 'OPTIONS']
7
+ IDEMPOTENT_METHODS = ['PUT', 'PATCH', 'DELETE']
8
+ UNSAFE_METHODS = ['POST']
9
+
10
+ attr_reader :rel
11
+
12
+ def self.call(arg)
13
+ new(arg).to_hash
14
+ end
15
+
16
+ def initialize(rel)
17
+ @rel = rel
18
+ end
19
+
20
+ def to_hash
21
+ {
22
+ id: rel.id,
23
+ type: type,
24
+ }.merge(optional_properties)
25
+ end
26
+
27
+ private
28
+
29
+ def optional_properties
30
+ descriptors = serialized_descriptors
31
+ hash = {}
32
+ hash[:href] = rel.href if rel.href
33
+ hash[:doc] = { value: rel.doc } if rel.doc
34
+ hash[:name] = rel.name.to_s if rel.name
35
+ hash[:rt] = rel.content_type if rel.content_type
36
+ hash[:descriptor] = descriptors unless descriptors.empty?
37
+ hash[:ext] = extension if extension
38
+ hash
39
+ end
40
+
41
+ def type
42
+ methods = rel.http_methods
43
+ if methods.all? { |m| SAFE_METHODS.include? m }
44
+ 'safe'
45
+ elsif methods.all? { |m| (SAFE_METHODS + IDEMPOTENT_METHODS).include? m }
46
+ 'idempotent'
47
+ else
48
+ 'unsafe'
49
+ end
50
+ end
51
+
52
+ def extension
53
+ methods = rel.http_methods
54
+ return unless methods
55
+
56
+ [
57
+ {
58
+ id: :http_method,
59
+ href: 'https://gist.github.com/sammyhenningsson/2103d839eb79a7baf8854bfb96bda7ae',
60
+ value: methods,
61
+ }
62
+ ]
63
+ end
64
+
65
+ def serialized_descriptors
66
+ rel.attributes.map { |attr| AttributeSerializer.call(attr) }
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,77 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'net/http'
4
+ require 'tempfile'
5
+ require 'uri'
6
+ require 'csv'
7
+
8
+ module Shaf
9
+ module ApiDoc
10
+ class LinkRelations
11
+ class LinkRelation
12
+ attr_reader :name, :description, :reference, :notes
13
+
14
+ def initialize(name, description, reference, notes)
15
+ @name = name.to_sym
16
+ @description = description.freeze
17
+ @reference = reference.freeze
18
+ @notes = notes.freeze
19
+ end
20
+ end
21
+
22
+ class << self
23
+ IANA_URL = URI('https://www.iana.org/assignments/link-relations/link-relations-1.csv')
24
+
25
+ def all
26
+ relations.values
27
+ end
28
+
29
+ def [](key)
30
+ relations[key]
31
+ end
32
+
33
+ def []=(key, value)
34
+ relations[key] = value
35
+ end
36
+
37
+ def add(link_relation)
38
+ relations[link_relation.name] = link_relation
39
+ end
40
+
41
+ def load_iana
42
+ csv.each do |name, desc, ref, notes|
43
+ next if name == 'Relation Name'
44
+ add LinkRelation.new(name, desc, ref, notes)
45
+ end
46
+ end
47
+
48
+ private
49
+
50
+ def relations
51
+ @relations ||= {}
52
+ end
53
+
54
+ def tmp_file_name
55
+ File.join(Dir.tmpdir, 'shaf_iana_link_relations')
56
+ end
57
+
58
+ def csv
59
+ if File.readable? tmp_file_name
60
+ content = File.read(tmp_file_name)
61
+ return CSV.new(content)
62
+ end
63
+
64
+ response = Net::HTTP.get_response(IANA_URL)
65
+
66
+ if response.code.to_i == 200
67
+ content = response.body
68
+ File.open(tmp_file_name, 'w') { |file| file.write(content) }
69
+ CSV.new(content)
70
+ else
71
+ Utils.iana_link_relations_csv
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,56 @@
1
+ require 'set'
2
+ require 'digest'
3
+ require 'shaf/authenticator/request'
4
+
5
+ module Shaf
6
+ module Authenticator
7
+ class << self
8
+ def register(authenticator)
9
+ authenticators << authenticator
10
+ end
11
+
12
+ def unregister(authenticator)
13
+ authenticators.delete_if { |auth| auth == authenticator }
14
+ end
15
+
16
+ def challenges_for(realm: nil)
17
+ authenticators.each_with_object([]) do |authenticator, challenges|
18
+ challenges.concat Array(authenticator.challenges_for(realm))
19
+ end
20
+ end
21
+
22
+ def user(env, realm: nil)
23
+ request = Request.new(env)
24
+ return unless request.provided?
25
+
26
+ authenticator = authenticator_for(request)
27
+ authenticator&.user(request, realm: realm)
28
+ end
29
+
30
+ private
31
+
32
+ def authenticators
33
+ @authenticators ||= Set.new
34
+ end
35
+
36
+ def authenticator_for(request)
37
+ scheme = request.scheme
38
+ authenticator = authenticators.find { |auth| auth.scheme? scheme }
39
+
40
+ logger.warn(
41
+ "Client tried to authenticate with an unsupported " \
42
+ "authentication scheme: #{scheme}"
43
+ ) unless authenticator
44
+
45
+ authenticator
46
+ end
47
+
48
+ def logger
49
+ Shaf.logger
50
+ end
51
+ end
52
+ end
53
+ end
54
+
55
+ require 'shaf/authenticator/base'
56
+ require 'shaf/authenticator/basic_auth'
@@ -0,0 +1,161 @@
1
+ require 'shaf/authenticator/challenge'
2
+ require 'shaf/authenticator/parameter'
3
+ require 'shaf/errors'
4
+
5
+ module Shaf
6
+ module Authenticator
7
+ class Base
8
+ class MissingParametersError < Error
9
+ def initialize(authenticator, *args)
10
+ super("Missing required parameters: [#{args.join(', ')}] for #{authenticator}")
11
+ end
12
+ end
13
+
14
+ class InvalidParameterError < Error
15
+ def initialize(authenticator, *args)
16
+ str = args.map { |key, value| "#{key}: #{value}" }.join(', ')
17
+ super("Invalid parameters for #{authenticator}: #{str}")
18
+ end
19
+ end
20
+
21
+ class WrongCredentialsReturnTypeError < Error
22
+ def initialize(authenticator, clazz)
23
+ super <<~ERR
24
+ #{authenticator}.credentials return an instance of #{clazz}
25
+ It must return an instance of Hash.
26
+ Location: #{authenticator.method(:credentials).source_location})
27
+ ERR
28
+ end
29
+ end
30
+
31
+ class << self
32
+ def inherited(child)
33
+ Authenticator.register(child)
34
+ end
35
+
36
+ def scheme(scheme = nil)
37
+ if scheme
38
+ @scheme = scheme.to_s
39
+ elsif @scheme
40
+ @scheme
41
+ else
42
+ raise Error, "#{self} must specify a scheme!"
43
+ end
44
+ end
45
+
46
+ def scheme?(str)
47
+ return false unless scheme
48
+
49
+ str.to_s.downcase == scheme.downcase
50
+ end
51
+
52
+ def param(name, required: true, default: nil, values: nil)
53
+ params[name.to_sym] = Parameter.new(
54
+ name,
55
+ required: required,
56
+ default: default,
57
+ values: values
58
+ )
59
+ end
60
+
61
+ def restricted(**parameters, &block)
62
+ validate! parameters
63
+ add_defaults! parameters
64
+ challenges << Challenge.new(scheme, **parameters, &block)
65
+ end
66
+
67
+ def challenges_for(realm)
68
+ challenges.select do |challenge|
69
+ challenge.realm? realm
70
+ end
71
+ end
72
+
73
+ def user(request, realm: nil)
74
+ auth = authorization(request)
75
+ cred = credentials(auth, request) || {}
76
+ raise WrongCredentialsReturnTypeError.new(self, cred.class) unless cred.kind_of? Hash
77
+
78
+ return if cred.compact.empty?
79
+
80
+ challenges_for(realm).each do |challenge|
81
+ user = challenge.test(**cred)
82
+ return user if user
83
+ end
84
+
85
+ nil
86
+ end
87
+
88
+ def params
89
+ @params ||= superclass.respond_to?(:params) ? superclass.params.dup : {}
90
+ end
91
+
92
+ protected
93
+
94
+ # Subclasses should implement this method. The return value should be and array
95
+ # that will get passed as block arguments to the block passed to #restricted
96
+ def credentials(authorization, request); end
97
+
98
+ private
99
+
100
+ def challenges
101
+ @challenges ||= []
102
+ end
103
+
104
+ def validate!(parameters)
105
+ validate_required(parameters)
106
+ validate_params(parameters)
107
+ end
108
+
109
+ def validate_required(parameters)
110
+ errors = []
111
+
112
+ required_params.each do |param|
113
+ next if parameters.key? param.name
114
+ next if param.default
115
+ errors << param.name
116
+ end
117
+
118
+ raise MissingParametersError.new(self, *errors) unless errors.empty?
119
+ end
120
+
121
+ def validate_params(parameters)
122
+ errors = []
123
+
124
+ parameters.each do |key, value|
125
+ if params.key? key
126
+ errors << [key, value] unless params[key].valid? value
127
+ else
128
+ logger.warn "Unsupported authenticator parameter " \
129
+ "for #{self}: #{key} = \"#{value}\""
130
+ parameters.delete(key)
131
+ end
132
+ end
133
+
134
+ raise InvalidParameterError.new(self, *errors) unless errors.empty?
135
+ end
136
+
137
+ def logger
138
+ Shaf.logger
139
+ end
140
+
141
+ def add_defaults!(parameters)
142
+ params.each do |key, param|
143
+ next unless param.default
144
+ parameters[key] ||= param.default
145
+ end
146
+ end
147
+
148
+ def required_params
149
+ params.values.select(&:required?)
150
+ end
151
+
152
+ def authorization(request)
153
+ return unless request.authorization
154
+
155
+ request.authorization.sub(/^#{scheme} /i, '')
156
+ end
157
+ end
158
+ end
159
+ end
160
+ end
161
+