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.
- data/CHANGELOG.md +210 -0
- data/README.md +282 -0
- data/assets/aker/form/login.css +73 -0
- data/assets/aker/form/login.html.erb +44 -0
- data/lib/aker/authorities/automatic_access.rb +36 -0
- data/lib/aker/authorities/composite.rb +301 -0
- data/lib/aker/authorities/static.rb +283 -0
- data/lib/aker/authorities/support/find_sole_user.rb +24 -0
- data/lib/aker/authorities/support.rb +9 -0
- data/lib/aker/authorities.rb +46 -0
- data/lib/aker/cas/authority.rb +79 -0
- data/lib/aker/cas/configuration_helper.rb +85 -0
- data/lib/aker/cas/middleware/logout_responder.rb +49 -0
- data/lib/aker/cas/middleware/ticket_remover.rb +35 -0
- data/lib/aker/cas/middleware.rb +6 -0
- data/lib/aker/cas/proxy_mode.rb +108 -0
- data/lib/aker/cas/rack_proxy_callback.rb +188 -0
- data/lib/aker/cas/service_mode.rb +88 -0
- data/lib/aker/cas/service_url.rb +62 -0
- data/lib/aker/cas/user_ext.rb +64 -0
- data/lib/aker/cas.rb +31 -0
- data/lib/aker/central_parameters.rb +101 -0
- data/lib/aker/configuration.rb +534 -0
- data/lib/aker/deprecation.rb +105 -0
- data/lib/aker/form/custom_views_mode.rb +80 -0
- data/lib/aker/form/login_form_asset_provider.rb +56 -0
- data/lib/aker/form/middleware/custom_view_login_responder.rb +19 -0
- data/lib/aker/form/middleware/login_renderer.rb +72 -0
- data/lib/aker/form/middleware/login_responder.rb +71 -0
- data/lib/aker/form/middleware/logout_responder.rb +26 -0
- data/lib/aker/form/middleware.rb +10 -0
- data/lib/aker/form/mode.rb +118 -0
- data/lib/aker/form.rb +26 -0
- data/lib/aker/group.rb +67 -0
- data/lib/aker/group_membership.rb +162 -0
- data/lib/aker/ldap/authority.rb +392 -0
- data/lib/aker/ldap/user_ext.rb +19 -0
- data/lib/aker/ldap.rb +22 -0
- data/lib/aker/modes/base.rb +85 -0
- data/lib/aker/modes/http_basic.rb +100 -0
- data/lib/aker/modes/support/attempted_path.rb +22 -0
- data/lib/aker/modes/support/rfc_2617.rb +32 -0
- data/lib/aker/modes/support.rb +12 -0
- data/lib/aker/modes.rb +48 -0
- data/lib/aker/rack/authenticate.rb +37 -0
- data/lib/aker/rack/configuration_helper.rb +18 -0
- data/lib/aker/rack/default_logout_responder.rb +36 -0
- data/lib/aker/rack/environment_helper.rb +34 -0
- data/lib/aker/rack/facade.rb +102 -0
- data/lib/aker/rack/failure.rb +69 -0
- data/lib/aker/rack/logout.rb +63 -0
- data/lib/aker/rack/request_ext.rb +19 -0
- data/lib/aker/rack/session_timer.rb +95 -0
- data/lib/aker/rack/setup.rb +77 -0
- data/lib/aker/rack.rb +107 -0
- data/lib/aker/test/helpers.rb +22 -0
- data/lib/aker/test.rb +8 -0
- data/lib/aker/user.rb +231 -0
- data/lib/aker/version.rb +3 -0
- data/lib/aker.rb +51 -0
- data/spec/aker/aker-sample.yml +11 -0
- data/spec/aker/authorities/automatic_access_spec.rb +52 -0
- data/spec/aker/authorities/composite_spec.rb +488 -0
- data/spec/aker/authorities/nu-schema.jar +0 -0
- data/spec/aker/authorities/static_spec.rb +455 -0
- data/spec/aker/authorities/support/find_sole_user_spec.rb +33 -0
- data/spec/aker/authorities_spec.rb +16 -0
- data/spec/aker/cas/authority_spec.rb +106 -0
- data/spec/aker/cas/configuration_helper_spec.rb +92 -0
- data/spec/aker/cas/middleware/logout_responder_spec.rb +47 -0
- data/spec/aker/cas/middleware/ticket_remover_spec.rb +49 -0
- data/spec/aker/cas/proxy_mode_spec.rb +185 -0
- data/spec/aker/cas/rack_proxy_callback_spec.rb +190 -0
- data/spec/aker/cas/service_mode_spec.rb +122 -0
- data/spec/aker/cas/service_url_spec.rb +114 -0
- data/spec/aker/cas/user_ext_spec.rb +27 -0
- data/spec/aker/cas_spec.rb +19 -0
- data/spec/aker/central_parameters_spec.rb +44 -0
- data/spec/aker/configuration_spec.rb +465 -0
- data/spec/aker/deprecation_spec.rb +115 -0
- data/spec/aker/form/a_form_mode.rb +129 -0
- data/spec/aker/form/custom_views_mode_spec.rb +34 -0
- data/spec/aker/form/login_form_asset_provider_spec.rb +80 -0
- data/spec/aker/form/middleware/a_form_login_responder.rb +89 -0
- data/spec/aker/form/middleware/custom_view_login_responder_spec.rb +47 -0
- data/spec/aker/form/middleware/login_renderer_spec.rb +56 -0
- data/spec/aker/form/middleware/login_responder_spec.rb +34 -0
- data/spec/aker/form/middleware/logout_responder_spec.rb +55 -0
- data/spec/aker/form/mode_spec.rb +15 -0
- data/spec/aker/form_spec.rb +11 -0
- data/spec/aker/group_membership_spec.rb +208 -0
- data/spec/aker/group_spec.rb +66 -0
- data/spec/aker/ldap/authority_spec.rb +414 -0
- data/spec/aker/ldap/ldap-users.ldif +197 -0
- data/spec/aker/ldap_spec.rb +11 -0
- data/spec/aker/modes/a_aker_mode.rb +41 -0
- data/spec/aker/modes/http_basic_spec.rb +127 -0
- data/spec/aker/modes/support/attempted_path_spec.rb +32 -0
- data/spec/aker/modes_spec.rb +11 -0
- data/spec/aker/rack/authenticate_spec.rb +78 -0
- data/spec/aker/rack/default_logout_responder_spec.rb +67 -0
- data/spec/aker/rack/facade_spec.rb +154 -0
- data/spec/aker/rack/failure_spec.rb +151 -0
- data/spec/aker/rack/logout_spec.rb +63 -0
- data/spec/aker/rack/request_ext_spec.rb +29 -0
- data/spec/aker/rack/session_timer_spec.rb +134 -0
- data/spec/aker/rack/setup_spec.rb +87 -0
- data/spec/aker/rack_spec.rb +216 -0
- data/spec/aker/test/helpers_spec.rb +44 -0
- data/spec/aker/user_spec.rb +362 -0
- data/spec/aker_spec.rb +80 -0
- data/spec/deprecation_helper.rb +58 -0
- data/spec/java_helper.rb +5 -0
- data/spec/logger_helper.rb +17 -0
- data/spec/matchers.rb +31 -0
- data/spec/mock_builder.rb +25 -0
- data/spec/spec_helper.rb +52 -0
- 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
|