aker 3.0.0.pre

Sign up to get free protection for your applications and to get access to all the features.
Files changed (118) hide show
  1. data/CHANGELOG.md +210 -0
  2. data/README.md +282 -0
  3. data/assets/aker/form/login.css +73 -0
  4. data/assets/aker/form/login.html.erb +44 -0
  5. data/lib/aker/authorities/automatic_access.rb +36 -0
  6. data/lib/aker/authorities/composite.rb +301 -0
  7. data/lib/aker/authorities/static.rb +283 -0
  8. data/lib/aker/authorities/support/find_sole_user.rb +24 -0
  9. data/lib/aker/authorities/support.rb +9 -0
  10. data/lib/aker/authorities.rb +46 -0
  11. data/lib/aker/cas/authority.rb +79 -0
  12. data/lib/aker/cas/configuration_helper.rb +85 -0
  13. data/lib/aker/cas/middleware/logout_responder.rb +49 -0
  14. data/lib/aker/cas/middleware/ticket_remover.rb +35 -0
  15. data/lib/aker/cas/middleware.rb +6 -0
  16. data/lib/aker/cas/proxy_mode.rb +108 -0
  17. data/lib/aker/cas/rack_proxy_callback.rb +188 -0
  18. data/lib/aker/cas/service_mode.rb +88 -0
  19. data/lib/aker/cas/service_url.rb +62 -0
  20. data/lib/aker/cas/user_ext.rb +64 -0
  21. data/lib/aker/cas.rb +31 -0
  22. data/lib/aker/central_parameters.rb +101 -0
  23. data/lib/aker/configuration.rb +534 -0
  24. data/lib/aker/deprecation.rb +105 -0
  25. data/lib/aker/form/custom_views_mode.rb +80 -0
  26. data/lib/aker/form/login_form_asset_provider.rb +56 -0
  27. data/lib/aker/form/middleware/custom_view_login_responder.rb +19 -0
  28. data/lib/aker/form/middleware/login_renderer.rb +72 -0
  29. data/lib/aker/form/middleware/login_responder.rb +71 -0
  30. data/lib/aker/form/middleware/logout_responder.rb +26 -0
  31. data/lib/aker/form/middleware.rb +10 -0
  32. data/lib/aker/form/mode.rb +118 -0
  33. data/lib/aker/form.rb +26 -0
  34. data/lib/aker/group.rb +67 -0
  35. data/lib/aker/group_membership.rb +162 -0
  36. data/lib/aker/ldap/authority.rb +392 -0
  37. data/lib/aker/ldap/user_ext.rb +19 -0
  38. data/lib/aker/ldap.rb +22 -0
  39. data/lib/aker/modes/base.rb +85 -0
  40. data/lib/aker/modes/http_basic.rb +100 -0
  41. data/lib/aker/modes/support/attempted_path.rb +22 -0
  42. data/lib/aker/modes/support/rfc_2617.rb +32 -0
  43. data/lib/aker/modes/support.rb +12 -0
  44. data/lib/aker/modes.rb +48 -0
  45. data/lib/aker/rack/authenticate.rb +37 -0
  46. data/lib/aker/rack/configuration_helper.rb +18 -0
  47. data/lib/aker/rack/default_logout_responder.rb +36 -0
  48. data/lib/aker/rack/environment_helper.rb +34 -0
  49. data/lib/aker/rack/facade.rb +102 -0
  50. data/lib/aker/rack/failure.rb +69 -0
  51. data/lib/aker/rack/logout.rb +63 -0
  52. data/lib/aker/rack/request_ext.rb +19 -0
  53. data/lib/aker/rack/session_timer.rb +95 -0
  54. data/lib/aker/rack/setup.rb +77 -0
  55. data/lib/aker/rack.rb +107 -0
  56. data/lib/aker/test/helpers.rb +22 -0
  57. data/lib/aker/test.rb +8 -0
  58. data/lib/aker/user.rb +231 -0
  59. data/lib/aker/version.rb +3 -0
  60. data/lib/aker.rb +51 -0
  61. data/spec/aker/aker-sample.yml +11 -0
  62. data/spec/aker/authorities/automatic_access_spec.rb +52 -0
  63. data/spec/aker/authorities/composite_spec.rb +488 -0
  64. data/spec/aker/authorities/nu-schema.jar +0 -0
  65. data/spec/aker/authorities/static_spec.rb +455 -0
  66. data/spec/aker/authorities/support/find_sole_user_spec.rb +33 -0
  67. data/spec/aker/authorities_spec.rb +16 -0
  68. data/spec/aker/cas/authority_spec.rb +106 -0
  69. data/spec/aker/cas/configuration_helper_spec.rb +92 -0
  70. data/spec/aker/cas/middleware/logout_responder_spec.rb +47 -0
  71. data/spec/aker/cas/middleware/ticket_remover_spec.rb +49 -0
  72. data/spec/aker/cas/proxy_mode_spec.rb +185 -0
  73. data/spec/aker/cas/rack_proxy_callback_spec.rb +190 -0
  74. data/spec/aker/cas/service_mode_spec.rb +122 -0
  75. data/spec/aker/cas/service_url_spec.rb +114 -0
  76. data/spec/aker/cas/user_ext_spec.rb +27 -0
  77. data/spec/aker/cas_spec.rb +19 -0
  78. data/spec/aker/central_parameters_spec.rb +44 -0
  79. data/spec/aker/configuration_spec.rb +465 -0
  80. data/spec/aker/deprecation_spec.rb +115 -0
  81. data/spec/aker/form/a_form_mode.rb +129 -0
  82. data/spec/aker/form/custom_views_mode_spec.rb +34 -0
  83. data/spec/aker/form/login_form_asset_provider_spec.rb +80 -0
  84. data/spec/aker/form/middleware/a_form_login_responder.rb +89 -0
  85. data/spec/aker/form/middleware/custom_view_login_responder_spec.rb +47 -0
  86. data/spec/aker/form/middleware/login_renderer_spec.rb +56 -0
  87. data/spec/aker/form/middleware/login_responder_spec.rb +34 -0
  88. data/spec/aker/form/middleware/logout_responder_spec.rb +55 -0
  89. data/spec/aker/form/mode_spec.rb +15 -0
  90. data/spec/aker/form_spec.rb +11 -0
  91. data/spec/aker/group_membership_spec.rb +208 -0
  92. data/spec/aker/group_spec.rb +66 -0
  93. data/spec/aker/ldap/authority_spec.rb +414 -0
  94. data/spec/aker/ldap/ldap-users.ldif +197 -0
  95. data/spec/aker/ldap_spec.rb +11 -0
  96. data/spec/aker/modes/a_aker_mode.rb +41 -0
  97. data/spec/aker/modes/http_basic_spec.rb +127 -0
  98. data/spec/aker/modes/support/attempted_path_spec.rb +32 -0
  99. data/spec/aker/modes_spec.rb +11 -0
  100. data/spec/aker/rack/authenticate_spec.rb +78 -0
  101. data/spec/aker/rack/default_logout_responder_spec.rb +67 -0
  102. data/spec/aker/rack/facade_spec.rb +154 -0
  103. data/spec/aker/rack/failure_spec.rb +151 -0
  104. data/spec/aker/rack/logout_spec.rb +63 -0
  105. data/spec/aker/rack/request_ext_spec.rb +29 -0
  106. data/spec/aker/rack/session_timer_spec.rb +134 -0
  107. data/spec/aker/rack/setup_spec.rb +87 -0
  108. data/spec/aker/rack_spec.rb +216 -0
  109. data/spec/aker/test/helpers_spec.rb +44 -0
  110. data/spec/aker/user_spec.rb +362 -0
  111. data/spec/aker_spec.rb +80 -0
  112. data/spec/deprecation_helper.rb +58 -0
  113. data/spec/java_helper.rb +5 -0
  114. data/spec/logger_helper.rb +17 -0
  115. data/spec/matchers.rb +31 -0
  116. data/spec/mock_builder.rb +25 -0
  117. data/spec/spec_helper.rb +52 -0
  118. metadata +265 -0
@@ -0,0 +1,534 @@
1
+ require 'aker'
2
+
3
+ # can't do just core_ext/string in AS 2.3
4
+ require 'active_support/core_ext'
5
+
6
+ module Aker
7
+ ##
8
+ # The representation of a configuration for Aker in a particular
9
+ # application, including authorities, customization parameters, and
10
+ # authentication modes.
11
+ class Configuration
12
+ class << self
13
+ ##
14
+ # The default set of {Slice slices}. These will be applied to
15
+ # all newly created instances. Changes to this array will not be
16
+ # reflected in existing configuration instances.
17
+ #
18
+ # @since 2.2.0
19
+ # @return [Array<Slice>]
20
+ def default_slices
21
+ @default_slices ||= []
22
+ end
23
+
24
+ ##
25
+ # Appends a slice to the default set of slices. A slice may be
26
+ # specified either as a {Slice} instance or as a block provided
27
+ # directly to this method.
28
+ #
29
+ # @example from an instance
30
+ # class SomeSlice < Aker::Configuration::Slice
31
+ # def initialize
32
+ # super do
33
+ # register_authority :static, Aker::Authorities::Static
34
+ # end
35
+ # end
36
+ # end
37
+ # Aker::Configuration.add_default_slice(SomeSlice.new)
38
+ # @example from a block
39
+ # Aker::Configuration.add_default_slice do
40
+ # register_authority :static, Aker::Authorities::Static
41
+ # end
42
+ #
43
+ # @since 2.2.0
44
+ # @param [Slice] slice the slice to add, if a block isn't
45
+ # provided.
46
+ # @return [void]
47
+ def add_default_slice(slice=nil, &block)
48
+ if slice
49
+ default_slices << slice
50
+ end
51
+ if block
52
+ default_slices << Slice.new(&block)
53
+ end
54
+ end
55
+ end
56
+
57
+ ##
58
+ # Creates a new configuration. If a block is given, it will be
59
+ # evaluated using the {ConfiguratorLanguage DSL} and appended to
60
+ # the new instance.
61
+ #
62
+ # @param [Hash] options
63
+ #
64
+ # @option options [Array<Slice>] :slices substitutes a set of
65
+ # slices for the {.default_slices globally-configured defaults}.
66
+ # This will only be necessary in very rare situations.
67
+ def initialize(options={}, &config)
68
+ (options[:slices] || self.class.default_slices).each do |slice|
69
+ self.enhance(&slice.contents)
70
+ end
71
+ self.enhance(&config) if config
72
+ end
73
+
74
+ ##
75
+ # Updates the configuration via the {ConfiguratorLanguage DSL}.
76
+ #
77
+ # @return [Configuration] itself
78
+ def enhance(&additional_config)
79
+ Configurator.new(self, &additional_config)
80
+ self
81
+ end
82
+
83
+ ##
84
+ # @return [Symbol] the name of the configured interactive authentication
85
+ # mode. Default is `:form`.
86
+ def ui_mode
87
+ @ui_mode ||= :form
88
+ end
89
+
90
+ ##
91
+ # Sets the interactive authentication mode.
92
+ # @param [#to_sym, nil] ui_mode the name of the new mode; if nil,
93
+ # reset to the default
94
+ # @return [void]
95
+ def ui_mode=(ui_mode)
96
+ @ui_mode = nil_or_sym(ui_mode)
97
+ end
98
+
99
+ ##
100
+ # @return [Array<Symbol>] the names of the configured non-interactive
101
+ # authentication modes. Default is an empty list.
102
+ def api_modes
103
+ @api_modes ||= []
104
+ end
105
+
106
+ ##
107
+ # Replaces the non-interactive authentication modes.
108
+ # @param [List<#to_sym>] new_modes the names of the desired modes
109
+ # @return [void]
110
+ def api_modes=(*new_modes)
111
+ new_modes = new_modes.first if new_modes.size == 1 && Array === new_modes.first
112
+ @api_modes = new_modes.compact.collect(&:to_sym)
113
+ end
114
+ alias :api_mode= :api_modes=
115
+
116
+ ##
117
+ # @return [Symbol] the portal to which this application belongs
118
+ def portal
119
+ raise "No portal configured" unless portal?
120
+ @portal
121
+ end
122
+
123
+ ##
124
+ # Set the portal to which this application belongs.
125
+ #
126
+ # Portal is an optional authorization concept. If you have an
127
+ # authority which is based on an authorization store that provides
128
+ # group information for multiple groups of applications, Aker
129
+ # calls each group of applications a portal.
130
+ #
131
+ # When an application declares that it is a part of a portal,
132
+ # authentication will fail for any user which is not a member of
133
+ # that portal. If you don't have an authority that provides that
134
+ # information, don't set a portal.
135
+ #
136
+ # @see Aker::User#portals
137
+ # @param [#to_sym] the new portal's name
138
+ # @return [void]
139
+ def portal=(portal)
140
+ @portal = nil_or_sym(portal)
141
+ end
142
+
143
+ ##
144
+ # @return [Boolean] true if there is a portal set, else false
145
+ def portal?
146
+ @portal
147
+ end
148
+
149
+ ##
150
+ # Returns the actual authority objects created based on the last
151
+ # call to {#authorities=}. Note that "authority" is concept and a
152
+ # set of methods (all of them optional), not a base class; see
153
+ # {Aker::Authorities::Composite} for more details.
154
+ #
155
+ # @return [Array<Object>] the actual authority objects specified
156
+ # by this configuration
157
+ def authorities
158
+ raise "No authorities configured" unless authorities?
159
+ @authorities
160
+ end
161
+
162
+ ##
163
+ # Set the authorities for this configuration.
164
+ #
165
+ # @param [Array<Symbol, String, Class, Object>] new_authorities
166
+ # each authority specification may take one of four forms.
167
+ #
168
+ # * A `Symbol` or a `String` will be resolved as an alias per
169
+ # the {#authority_aliases}. The {Aker::Authorities}
170
+ # documentation lists the built-in aliases. Extensions may
171
+ # provide others.
172
+ # * A `Class` will be instantiated, passing the
173
+ # configuration (this object) as the sole constructor
174
+ # parameter.
175
+ # * Any other object will be used unchanged.
176
+ #
177
+ # @return [void]
178
+ def authorities=(new_authorities)
179
+ @authorities = new_authorities.collect { |a| build_authority(a) }
180
+ end
181
+
182
+ ##
183
+ # @return [Boolean] true if there are any authorities configured
184
+ def authorities?
185
+ @authorities && !@authorities.empty?
186
+ end
187
+
188
+ ##
189
+ # Exposes a single object which aggregates all the authorities in
190
+ # this configuration.
191
+ #
192
+ # @return [Aker::Authorities::Composite]
193
+ def composite_authority
194
+ @composite_authority ||= Aker::Authorities::Composite.new(self)
195
+ end
196
+
197
+ ##
198
+ # Returns the parameters for a particular group. Never returns `nil`.
199
+ #
200
+ # @param [Symbol] group the group of parameters to return
201
+ # @return [Hash] the parameters of the specified group.
202
+ def parameters_for(group)
203
+ @parameter_groups ||= { }
204
+ @parameter_groups[group] ||= { }
205
+ end
206
+
207
+ ##
208
+ # Merges the given parameters into the specified group's.
209
+ #
210
+ # @param [Symbol] group the target group
211
+ # @param [Hash] params the parameters to merge in
212
+ # @return [void]
213
+ def add_parameters_for(group, params)
214
+ nested_merge!(parameters_for(group), params)
215
+ end
216
+
217
+ ##
218
+ # Loads parameters from the given aker central parameters
219
+ # file.
220
+ #
221
+ # @see Aker::CentralParameters
222
+ # @param [String] filename the filename
223
+ # @return [void]
224
+ def central(filename)
225
+ params = ::Aker::CentralParameters.new(filename)
226
+
227
+ params.each { |k, v| add_parameters_for(k, v) }
228
+ end
229
+
230
+ ##
231
+ # Register an alias for an authority object. The alias is a symbol
232
+ # (or something that can be turned into one). The authority object
233
+ # is any single element that can be passed to {#authorities=}.
234
+ #
235
+ # Aker does and Aker extensions may define shorter aliases for
236
+ # the authorities that they provide. In general, it's not expected
237
+ # that applications, even if they provide their own authorities,
238
+ # will need to configure aliases.
239
+ #
240
+ # @param name [#to_sym] the alias itself
241
+ # @param authority [Symbol,String,Class,Object] the authority
242
+ # object to alias. See {#authorities=} for more details.
243
+ # @return [void]
244
+ def alias_authority(name, authority)
245
+ authority_aliases[name.to_sym] = authority
246
+ end
247
+
248
+ ##
249
+ # @see #alias_authority
250
+ # @return [Hash] the map of aliases to authority objects.
251
+ def authority_aliases
252
+ @authority_aliases ||= {}
253
+ end
254
+
255
+ ##
256
+ # Register a mode class to be used in this configuration. A mode
257
+ # class is a Warden strategy with some additional Aker elements on
258
+ # top.
259
+ #
260
+ # Aker and Aker extensions register the the modes that they
261
+ # provide (using {Slice slices}), so an application only needs to
262
+ # invoke this method if it provides its own custom mode.
263
+ #
264
+ # @see #registered_modes
265
+ # @see https://github.com/hassox/warden/wiki/Strategies
266
+ # @see Aker::Modes::Base
267
+ # @since 2.2.0
268
+ # @param mode_class [Class]
269
+ # @return [void]
270
+ def register_mode(mode_class)
271
+ fail "#{mode_class.inspect} is not usable as a Aker mode" unless mode_class.respond_to?(:key)
272
+ registered_modes << mode_class
273
+ end
274
+
275
+ ##
276
+ # The mode classes that have been registered for use in this
277
+ # configuration.
278
+ #
279
+ # @see #register_mode
280
+ # @return [Array<Class>]
281
+ def registered_modes
282
+ @registered_modes ||= []
283
+ end
284
+
285
+ ##
286
+ # Register a middleware-building block that will be used to insert
287
+ # middleware either before or after the Aker
288
+ # {Aker::Rack::Authenticate authentication middleware}. This
289
+ # method requires a block. When it is time to actually install the
290
+ # middleware, the block will be yielded an object which behaves
291
+ # like a `Rack::Builder`. The block should attach any middleware
292
+ # it wishes to install using `use`.
293
+ #
294
+ # Unlike the middleware associated with modes, this middleware
295
+ # will be inserted in the stack in regardless of any other
296
+ # settings.
297
+ #
298
+ # This method is primarily intended for Aker and Aker
299
+ # extensions. Applications have complete control over their
300
+ # middleware stacks and so may build them however is appropriate.
301
+ #
302
+ # @example
303
+ # config.register_middleware_installer(:before_authentication) do |builder|
304
+ # builder.use IpFilter, '10.0.8.9'
305
+ # end
306
+ #
307
+ # @see #install_middleware
308
+ # @see Aker::Rack.use_in
309
+ #
310
+ # @param [:before_authentication,:after_authentication] where the
311
+ # relative location in the stack at which this installer should
312
+ # be invoked.
313
+ # @yield [#use] a Rack::Builder. Note that the yield is deferred
314
+ # until {#install_middleware} is invoked.
315
+ # @return [void]
316
+ def register_middleware_installer(where, &installer)
317
+ verify_middleware_location(where)
318
+ (middleware_installers[where] ||= []) << installer
319
+ end
320
+
321
+ ##
322
+ # @private exposed for testing
323
+ def middleware_installers
324
+ @middleware_installers ||= {}
325
+ end
326
+
327
+ ##
328
+ # Installs the middleware configured under the given key in the
329
+ # given `Rack::Builder}. This method is primarily for internal
330
+ # library use.
331
+ #
332
+ # @see #register_middleware_installer
333
+ # @param [:before_authentication,:after_authentication] where the
334
+ # set of middleware installers to use.
335
+ # @param [#use] builder the `Rack::Builder`-like object into which
336
+ # the middleware will be installed.
337
+ # @return [void]
338
+ def install_middleware(where, builder)
339
+ verify_middleware_location(where)
340
+ (middleware_installers[where] || []).each do |installer|
341
+ installer.call(builder)
342
+ end
343
+ end
344
+
345
+ def verify_middleware_location(where)
346
+ unless [:before_authentication, :after_authentication].include?(where)
347
+ fail "Unsupported middleware location #{where.inspect}."
348
+ end
349
+ end
350
+ private :verify_middleware_location
351
+
352
+ ##
353
+ # Retrieves the logger which aker will use for internal messages.
354
+ #
355
+ # The default instance logs to standard error.
356
+ #
357
+ # @return [Object] an object which conforms to the
358
+ # protocol of ruby's built-in Logger class
359
+ def logger
360
+ @logger ||= Logger.new($stderr)
361
+ end
362
+
363
+ ##
364
+ # Specifies the logger aker will use for internal messages.
365
+ #
366
+ # @param [Object] logger an object which conforms to the protocol
367
+ # of ruby's built-in Logger class
368
+ def logger=(logger)
369
+ @logger = logger
370
+ end
371
+
372
+ private
373
+
374
+ def nil_or_sym(x)
375
+ x ? x.to_sym : x
376
+ end
377
+
378
+ def build_authority(spec)
379
+ case spec
380
+ when Symbol
381
+ resolve_alias(spec)
382
+ when String
383
+ resolve_alias(spec)
384
+ when Class
385
+ instantiate_authority(spec)
386
+ else # assume it's an instance
387
+ spec
388
+ end
389
+ end
390
+
391
+ def instantiate_authority(clazz)
392
+ clazz.new(self)
393
+ end
394
+
395
+ def resolve_alias(name)
396
+ resolved_spec = authority_aliases[name.to_sym]
397
+ fail "Unknown authority alias #{name.inspect}." unless resolved_spec
398
+ build_authority resolved_spec
399
+ end
400
+
401
+ def nested_merge!(target, overrides)
402
+ overrides.each_pair do |k, v|
403
+ if v.respond_to?(:each_pair)
404
+ if target.has_key?(k)
405
+ nested_merge!(target[k], overrides[k])
406
+ else
407
+ target[k] = overrides[k]
408
+ end
409
+ else
410
+ target[k] = v
411
+ end
412
+ end
413
+ target
414
+ end
415
+
416
+ ##
417
+ # A persistent, reappliable fragment of a {Aker::Configuration}.
418
+ # This class enables Aker extensions to provide default chunks of
419
+ # configuration that will apply to every newly-created
420
+ # configuration instance.
421
+ #
422
+ # In general this facility is not needed by applications that use
423
+ # Aker; it's intended only for libraries that provide additional
424
+ # functionality on top of Aker and need to provide reasonable
425
+ # defaults and/or mandatory infrastructure for those features.
426
+ #
427
+ # Extensions of that kind should create an instance of this class
428
+ # and register it with {Aker::Configuration.add_default_slice}
429
+ # (or pass a block to that method to have it create one on their
430
+ # behalf).
431
+ #
432
+ # Most of Aker's own functionality (including all authorities and
433
+ # modes) are registered using slices internally. If you are
434
+ # considering writing one, take a look at Aker's source for
435
+ # examples.
436
+ #
437
+ # @since 2.2.0
438
+ class Slice
439
+ ##
440
+ # @return [Proc] the configuration DSL fragment comprising this
441
+ # slice.
442
+ attr_accessor :contents
443
+
444
+ ##
445
+ # @param contents the configuration DSL fragment comprising this
446
+ # slice.
447
+ def initialize(&contents)
448
+ @contents = contents
449
+ end
450
+ end
451
+ end
452
+
453
+ ##
454
+ # This module provides a DSL adapter for {Configuration}.
455
+ #
456
+ # @example
457
+ # Aker.configure {
458
+ # portal :ENU
459
+ # authorities :ldap, :static
460
+ # api_mode :http_basic
461
+ # central "/etc/nubic/aker-prod.yml"
462
+ # ldap_parameters :server => 'ldap.example.org'
463
+ # after_authentication_middleware do |builder|
464
+ # builder.use RequestLogger
465
+ # end
466
+ # }
467
+ #
468
+ # Notes:
469
+ #
470
+ # * All setters in {Configuration} are accessible from the DSL,
471
+ # except that you don't use '='.
472
+ # * Other methods which accept arguments are also available.
473
+ # * As shown in the example, there is sugar for setting other parameters.
474
+ # "*name*_parameters *hash*" adds to the
475
+ # {Configuration#parameters_for parameters} for group *name*.
476
+ # * Also as shown in the example, there is sugar for calling
477
+ # {Configuration#register_middleware_installer}.
478
+ # * `this` refers to the configuration being updated (for the rare
479
+ # case that you would need to pass it directly to some constructor).
480
+ module ConfiguratorLanguage
481
+ ##
482
+ # @private
483
+ def authorities(*authorities)
484
+ @specified_authorities = authorities
485
+ end
486
+ alias authority authorities
487
+
488
+ ##
489
+ # @private
490
+ def method_missing(m, *args, &block)
491
+ if m.to_s =~ /(\S+)_parameters?$/
492
+ @config.add_parameters_for($1.to_sym, args.first)
493
+ elsif m.to_s =~/(\S+)_middleware$/
494
+ @config.register_middleware_installer($1.to_sym, &block)
495
+ elsif @config.respond_to?(:"#{m}=")
496
+ @config.send(:"#{m}=", *args)
497
+ elsif @config.respond_to?(m)
498
+ @config.send(m, *args)
499
+ else
500
+ super
501
+ end
502
+ end
503
+
504
+ ##
505
+ # @private
506
+ def this
507
+ @config
508
+ end
509
+
510
+ ##
511
+ # @private
512
+ def deferred_setup
513
+ @config.authorities = @specified_authorities if @specified_authorities
514
+ end
515
+ end
516
+
517
+ ##
518
+ # @private
519
+ class Configurator
520
+ include ConfiguratorLanguage
521
+
522
+ def initialize(target, &block)
523
+ @config = target
524
+ evaluate(&block)
525
+ end
526
+
527
+ private
528
+
529
+ def evaluate(&block)
530
+ instance_eval(&block)
531
+ deferred_setup
532
+ end
533
+ end
534
+ end
@@ -0,0 +1,105 @@
1
+ require 'aker'
2
+ require 'rubygems/version'
3
+
4
+ module Aker
5
+ ##
6
+ # Defines deprecation warnings and errors for pieces of the
7
+ # library which are being phased out.
8
+ #
9
+ # This is an internal API in Aker. If there's a use for it
10
+ # outside, it could be factored out.
11
+ module Deprecation
12
+ class << self
13
+ ##
14
+ # An object which determines what will happen to the messages
15
+ # generated by {.notify notify}. It should respond to one
16
+ # method; see {StderrMode#report StderrMode} for details.
17
+ #
18
+ # The default is an instance of {StderrMode}.
19
+ #
20
+ # @return [#report]
21
+ attr_accessor :mode
22
+
23
+ def mode
24
+ @mode ||= default_mode
25
+ end
26
+
27
+ ##
28
+ # Indicates that the method it was called from is deprecated and
29
+ # could be removed as of the specified version.
30
+ #
31
+ # @return [void]
32
+ def notify(message, version)
33
+ level = determine_level(version)
34
+ mode.report(level,
35
+ full_message_for(level, message, version,
36
+ caller[1].split('/').last.split(':')[0,2].join(':')),
37
+ version)
38
+ end
39
+
40
+ private
41
+
42
+ def default_mode
43
+ StderrMode.new
44
+ end
45
+
46
+ def determine_level(version)
47
+ if Gem::Version.new(version) <= Gem::Version.new(Aker::VERSION)
48
+ :obsolete
49
+ else
50
+ :deprecated
51
+ end
52
+ end
53
+
54
+ def full_message_for(level, message, version, line)
55
+ sprintf "%s: #{message} %s (Called from #{line}.)" %
56
+ (case level
57
+ when :deprecated
58
+ ["DEPRECATION WARNING",
59
+ "It will be removed from aker in version #{version} or later."]
60
+ when :obsolete
61
+ ["OBSOLETE API USED",
62
+ "It is no longer functional as of aker #{version} " <<
63
+ "and could be removed in any future version."]
64
+ else
65
+ raise "Unexpected level: #{level.inspect}"
66
+ end)
67
+ end
68
+ end
69
+
70
+ ##
71
+ # The default deprecation handler for Aker. When a deprecated
72
+ # method is invoked, it does one of two things:
73
+ #
74
+ # * If the method is only deprecated (i.e., slated for removal in
75
+ # a future release), it prints a warning to standard error.
76
+ # * If a method's deprecation version is passed, it throws an
77
+ # {ObsoleteError}.
78
+ #
79
+ # The motivation of the latter behavior is to force users to
80
+ # remove obsolete code before the hints about what to replace it
81
+ # with are removed.
82
+ class StderrMode
83
+ ##
84
+ # @param [:deprecated, :obsolete] level whether the called
85
+ # method is merely slated for removal or actually removed.
86
+ # @param [String] message the actual message, including information
87
+ # describing the level
88
+ # @param [String] version the version at which the code becomes
89
+ # obsolete
90
+ #
91
+ # @return [void]
92
+ def report(level, message, version)
93
+ case level
94
+ when :deprecated; $stderr.puts message;
95
+ when :obsolete; raise ObsoleteError.new(message)
96
+ end
97
+ end
98
+ end
99
+
100
+ ##
101
+ # The error thrown by {Aker::Deprecation::StderrMode} when
102
+ # obsolete code is invoked.
103
+ class ObsoleteError < StandardError; end
104
+ end
105
+ end
@@ -0,0 +1,80 @@
1
+ require 'aker'
2
+
3
+ module Aker::Form
4
+ ##
5
+ # A specialization of {Mode the :form mode} which allows the
6
+ # Aker-using application to provide the login and logout views.
7
+ #
8
+ # If you use this mode, your application is responsible for
9
+ # rendering appropriate views in response to `GET` to the login and
10
+ # logout paths. By default, the login and logout paths are `/login`
11
+ # and `/logout` (relative to your application). If your application
12
+ # uses other paths, you can change these to match via configuration
13
+ # parameters; see the example below.
14
+ #
15
+ # The login view may receive with one or more query parameters,
16
+ # depending on how the user is directed to it:
17
+ #
18
+ # * `url`: If the user is redirected to the login page after
19
+ # attempting to access a protected resource, the URL to the
20
+ # resource she was attempting to access will be passed as `url` in
21
+ # the query string.
22
+ # * `session_expired`: If the user is redirected to the login page
23
+ # because she made a request after her {Aker::Rack::SessionTimer
24
+ # session expired}, `session_expired=true` will be in the query
25
+ # string.
26
+ #
27
+ # The login view should arrange for the user's username and password
28
+ # to be `POST`ed to the login path using parameters with those
29
+ # names.
30
+ #
31
+ # If the form is being re-rendered because the user's credentials
32
+ # were rejected, the following variables will be available in the
33
+ # rack environment:
34
+ #
35
+ # * `aker.form.login_failed`: `true`
36
+ # * `aker.form.username`: the attempted username, if any
37
+ #
38
+ # In addition to re-rendering the form, It is the responsibility of
39
+ # the custom view to send the appropriate HTTP status (401) in this
40
+ # case.
41
+ #
42
+ # If the POST is successful, the user will be redirected to the
43
+ # originally requested URL (so long as it is still passed along in
44
+ # the `url` parameter). If there was no originally requested
45
+ # URL, the user will be redirected to the root of the application.
46
+ #
47
+ # The logout view may do whatever your application deems
48
+ # appropriate. If you don't provide a custom logout view, you will
49
+ # get the {Aker::Rack::DefaultLogoutResponder very spare default}.
50
+ #
51
+ # @example Configuring custom views and custom paths
52
+ # Aker.configure {
53
+ # authority :ldap
54
+ # ui_mode :custom_form
55
+ # rack_parameters :login_path => '/accts/log-in', :logout_path => '/accts/log-out'
56
+ # }
57
+ class CustomViewsMode < Mode
58
+ class << self
59
+ ##
60
+ # The configuration key for this mode.
61
+ # @return [:custom_form]
62
+ def key
63
+ :custom_form
64
+ end
65
+
66
+ ##
67
+ # Override parent to prepend nothing.
68
+ # @return [void]
69
+ def prepend_middleware(builder)
70
+ end
71
+
72
+ ##
73
+ # Override parent to append only {Middleware::CustomViewLoginResponder}.
74
+ # @return [void]
75
+ def append_middleware(builder)
76
+ builder.use Middleware::CustomViewLoginResponder
77
+ end
78
+ end
79
+ end
80
+ end