aker 3.0.0.pre

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 (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