merb_auth_slice_multisite 0.8.6

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 (37) hide show
  1. data/README.textile +147 -0
  2. data/VERSION.yml +4 -0
  3. data/app/controllers/application.rb +5 -0
  4. data/app/controllers/exceptions.rb +33 -0
  5. data/app/controllers/passwords.rb +29 -0
  6. data/app/controllers/sessions.rb +56 -0
  7. data/app/helpers/application_helper.rb +64 -0
  8. data/app/mailers/send_password_mailer.rb +11 -0
  9. data/app/mailers/views/send_password_mailer/send_password.text.erb +3 -0
  10. data/app/models/site.rb +26 -0
  11. data/app/views/exceptions/unauthenticated.html.erb +61 -0
  12. data/app/views/layout/merb_auth_slice_multisite.html.erb +16 -0
  13. data/config/database.yml +33 -0
  14. data/config/dependencies.rb +33 -0
  15. data/config/init.rb +84 -0
  16. data/config/router.rb +5 -0
  17. data/lib/merb-auth-more/strategies/multisite/multisite_password_form.rb +77 -0
  18. data/lib/merb-auth-remember-me/mixins/authenticated_user.rb +97 -0
  19. data/lib/merb-auth-remember-me/mixins/authenticated_user/dm_authenticated_user.rb +17 -0
  20. data/lib/merb-auth-remember-me/strategies/remember_me.rb +55 -0
  21. data/lib/merb_auth_slice_multisite.rb +107 -0
  22. data/lib/merb_auth_slice_multisite/merbtasks.rb +103 -0
  23. data/lib/merb_auth_slice_multisite/mixins/user_belongs_to_site.rb +63 -0
  24. data/lib/merb_auth_slice_multisite/mixins/user_belongs_to_site/dm_user_belongs_to_site.rb +28 -0
  25. data/lib/merb_auth_slice_multisite/slicetasks.rb +18 -0
  26. data/lib/merb_auth_slice_multisite/spectasks.rb +54 -0
  27. data/public/javascripts/master.js +0 -0
  28. data/public/stylesheets/master.css +2 -0
  29. data/spec/mailers/send_password_mailer_spec.rb +47 -0
  30. data/spec/mixins/authenticated_user_spec.rb +33 -0
  31. data/spec/mixins/user_belongs_to_site_spec.rb +56 -0
  32. data/spec/models/site_spec.rb +56 -0
  33. data/spec/spec_helper.rb +101 -0
  34. data/spec/strategies/remember_me_spec.rb +62 -0
  35. data/stubs/app/controllers/sessions.rb +19 -0
  36. data/stubs/app/views/exceptions/unauthenticated.html.erb +61 -0
  37. metadata +91 -0
@@ -0,0 +1,16 @@
1
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
2
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-us" lang="en-us">
3
+ <head>
4
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
5
+ <title>Fresh MerbAuthSliceMultisite Slice</title>
6
+ <link href="<%= public_path_for :stylesheet, 'master.css' %>" type="text/css" charset="utf-8" rel="stylesheet" media="all" />
7
+ <script src="<%= public_path_for :javascript, 'master.js' %>" type="text/javascript" charset="utf-8"></script>
8
+ </head>
9
+ <!-- you can override this layout at slices/merb_auth_slice_multisite/app/views/layout/merb_auth_slice_multisite.html.erb -->
10
+ <body class="merb_auth_slice_multisite-slice">
11
+ <div id="container">
12
+ <h1>MerbAuthSliceMultisite Slice</h1>
13
+ <div id="main"><%= catch_content :for_layout %></div>
14
+ </div>
15
+ </body>
16
+ </html>
@@ -0,0 +1,33 @@
1
+ ---
2
+ # This is a sample database file for the DataMapper ORM
3
+ development: &defaults
4
+ # These are the settings for repository :default
5
+ adapter: sqlite3
6
+ database: sample_development.db
7
+
8
+ # Add more repositories
9
+ # repositories:
10
+ # repo1:
11
+ # adapter: sqlite3
12
+ # database: sample_1_development.db
13
+ # repo2:
14
+ # ...
15
+
16
+ test:
17
+ <<: *defaults
18
+ database: sample_test.db
19
+
20
+ # repositories:
21
+ # repo1:
22
+ # database: sample_1_test.db
23
+
24
+ production:
25
+ <<: *defaults
26
+ database: production.db
27
+
28
+ # repositories:
29
+ # repo1:
30
+ # database: sample_production.db
31
+
32
+ rake:
33
+ <<: *defaults
@@ -0,0 +1,33 @@
1
+ # dependencies are generated using a strict version, don't forget to edit the dependency versions when upgrading.
2
+ merb_gems_version = "1.0.11"
3
+ dm_gems_version = "0.9.11"
4
+ do_gems_version = "0.9.11"
5
+
6
+ # For more information about each component, please read http://wiki.merbivore.com/faqs/merb_components
7
+ dependency "merb-core", merb_gems_version
8
+ dependency "merb-action-args", merb_gems_version
9
+ dependency "merb-assets", merb_gems_version
10
+ dependency("merb-cache", merb_gems_version) do
11
+ Merb::Cache.setup do
12
+ register(Merb::Cache::FileStore) unless Merb.cache
13
+ end
14
+ end
15
+ dependency "merb-helpers", merb_gems_version
16
+ dependency "merb-mailer", merb_gems_version
17
+ dependency "merb-slices", merb_gems_version
18
+ dependency "merb-auth-core", merb_gems_version
19
+ dependency "merb-auth-more", merb_gems_version
20
+ dependency "merb-auth-slice-password", merb_gems_version
21
+ dependency "merb-param-protection", merb_gems_version
22
+ dependency "merb-exceptions", merb_gems_version
23
+
24
+ dependency "data_objects", do_gems_version
25
+ dependency "dm-core", dm_gems_version
26
+ dependency "dm-aggregates", dm_gems_version
27
+ dependency "dm-migrations", dm_gems_version
28
+ dependency "dm-timestamps", dm_gems_version
29
+ dependency "dm-types", dm_gems_version
30
+ dependency "dm-validations", dm_gems_version
31
+ dependency "dm-serializer", dm_gems_version
32
+
33
+ dependency "merb_datamapper", merb_gems_version
@@ -0,0 +1,84 @@
1
+ #
2
+ # ==== Standalone MerbAuthSliceMultisite configuration
3
+ #
4
+ # This configuration/environment file is only loaded by bin/slice, which can be
5
+ # used during development of the slice. It has no effect on this slice being
6
+ # loaded in a host application. To run your slice in standalone mode, just
7
+ # run 'slice' from its directory. The 'slice' command is very similar to
8
+ # the 'merb' command, and takes all the same options, including -i to drop
9
+ # into an irb session for example.
10
+ #
11
+ # The usual Merb configuration directives and init.rb setup methods apply,
12
+ # including use_orm and before_app_loads/after_app_loads.
13
+ #
14
+ # If you need need different configurations for different environments you can
15
+ # even create the specific environment file in config/environments/ just like
16
+ # in a regular Merb application.
17
+ #
18
+ # In fact, a slice is no different from a normal # Merb application - it only
19
+ # differs by the fact that seamlessly integrates into a so called 'host'
20
+ # application, which in turn can override or finetune the slice implementation
21
+ # code and views.
22
+ #
23
+ require(File.join(File.expand_path(File.dirname(__FILE__)),"..","lib","merb_auth_slice_multisite"))
24
+
25
+ require 'config/dependencies.rb'
26
+ use_orm :datamapper
27
+ use_test :rspec
28
+ use_template_engine :erb
29
+
30
+ # Setup the required configuration for the slice
31
+ Merb::Slices::config[:merb_auth_slice_multisite][:send_password_from_email] = "no-reply@yourapp.com"
32
+ Merb::Slices::config[:merb_auth_slice_multisite][:domain] = "example.com"
33
+
34
+
35
+ Merb::BootLoader.before_app_loads do
36
+ DataMapper.setup(:default, "sqlite3::memory:")
37
+
38
+ class User
39
+ include DataMapper::Resource
40
+ include Merb::Authentication::Mixins::UserBelongsToSite
41
+ include Merb::Authentication::Mixins::AuthenticatedUser
42
+
43
+ property :id, Serial
44
+ property :email, String
45
+ property :login, String
46
+ property :password, String
47
+
48
+ belongs_to :site
49
+ end
50
+
51
+ class Merb::Authentication
52
+ def self.user_class
53
+ ::User
54
+ end
55
+
56
+ def store_user(user)
57
+ return nil if user.nil?
58
+ user.login
59
+ end
60
+ def fetch_user(user_id)
61
+ User.first(:login => login)
62
+ end
63
+ end
64
+ end
65
+
66
+
67
+ Merb::Config.use do |c|
68
+ # Sets up a custom session id key which is used for the session persistence
69
+ # cookie name. If not specified, defaults to '_session_id'.
70
+ # c[:session_id_key] = '_session_id'
71
+
72
+ # The session_secret_key is only required for the cookie session store.
73
+ c[:session_secret_key] = 'ef573d4e2d6f9bf3a713cd45eb4f9411dfba94ef'
74
+
75
+ # There are various options here, by default Merb comes with 'cookie',
76
+ # 'memory', 'memcache' or 'container'.
77
+ # You can of course use your favorite ORM instead:
78
+ # 'datamapper', 'sequel' or 'activerecord'.
79
+ c[:session_store] = 'cookie'
80
+
81
+ # When running a slice standalone, you're usually developing it,
82
+ # so enable template reloading by default.
83
+ c[:reload_templates] = true
84
+ end
@@ -0,0 +1,5 @@
1
+ # This file is here so slice can be testing as a stand alone application.
2
+
3
+ #Merb::Router.prepare do
4
+ # ...
5
+ #end
@@ -0,0 +1,77 @@
1
+ require 'merb-auth-more/strategies/abstract_password'
2
+ # This strategy uses a login, password, and site_id parameter.
3
+ #
4
+ # Overwrite the :password_param, :login_param, and :site_id_param
5
+ # to return the name of the field (on the form) that you're using the
6
+ # login with. These can be strings or symbols
7
+ #
8
+ # == Required
9
+ #
10
+ # === Methods
11
+ # <User>.authenticate(login_param, password_param)
12
+ #
13
+ class Merb::Authentication
14
+ module Strategies
15
+ module Multisite
16
+
17
+ # add site_id to base params.
18
+ # http://github.com/wycats/merb/blob/784ac7d71780d1a7cfb9152ba4cb0e
19
+ # 18a990ab7a/merb-auth/merb-auth-more/lib/merb-auth-more/
20
+ # strategies/abstract_password.rb
21
+ class Base < Merb::Authentication::Strategy
22
+ abstract!
23
+
24
+ # Overwrite this method to customize the field
25
+ def self.password_param
26
+ (Merb::Plugins.config[:"merb-auth"][:password_param] || :password).to_s.to_sym
27
+ end
28
+
29
+ # Overwrite this method to customize the field
30
+ def self.login_param
31
+ (Merb::Plugins.config[:"merb-auth"][:login_param] || :login).to_s.to_sym
32
+ end
33
+
34
+ # http://scottmotte.com/archives/194.html
35
+ def self.site_id_param
36
+ (Merb::Plugins.config[:"merb-auth"][:site_id_param] || :site_id).to_s.to_sym
37
+ end
38
+
39
+ def password_param
40
+ @password_param ||= Base.password_param
41
+ end
42
+
43
+ def login_param
44
+ @login_param ||= Base.login_param
45
+ end
46
+
47
+ # http://scottmotte.com/archives/194.html
48
+ def site_id_param
49
+ @site_id_param ||= Base.site_id_param
50
+ end
51
+ end
52
+
53
+ # custom strategy taking into account site_id and authenticating with it
54
+ # the authenticate method is already well defined so for now I made a muck of
55
+ # if/else statements
56
+ class Form < Base
57
+
58
+ def run!
59
+ if (login = request.params[login_param]) && (password = request.params[password_param]) && (site_id = request.params[site_id_param])
60
+ user = user_class.all(site_id_param => site_id).authenticate(login, password)
61
+ if !user
62
+ errors = request.session.authentication.errors
63
+ errors.clear!
64
+ errors.add(login_param, strategy_error_message)
65
+ end
66
+ user
67
+ end
68
+ end # run!
69
+
70
+ def strategy_error_message
71
+ "#{login_param.to_s.capitalize} or #{password_param.to_s.capitalize} were incorrect"
72
+ end
73
+
74
+ end # Form
75
+ end # Multisite Password
76
+ end # Strategies
77
+ end # Authentication
@@ -0,0 +1,97 @@
1
+ require "digest/sha1"
2
+ module Merb
3
+ class Authentication
4
+ module Mixins
5
+ # This mixin provides basic user remember token.
6
+ #
7
+ # Added properties:
8
+ # :remember_token_expires_at, DateTime
9
+ # :remember_token, String
10
+ #
11
+ # To use it simply require it and include it into your user class.
12
+ #
13
+ # class User
14
+ # include Merb::Authentication::Mixins::AuthenticatedUser
15
+ #
16
+ # end
17
+ #
18
+ module AuthenticatedUser
19
+ def self.included(base)
20
+ base.class_eval do
21
+ include Merb::Authentication::Mixins::AuthenticatedUser::InstanceMethods
22
+ extend Merb::Authentication::Mixins::AuthenticatedUser::ClassMethods
23
+
24
+ path = File.expand_path(File.dirname(__FILE__)) / "authenticated_user"
25
+ if defined?(DataMapper) && DataMapper::Resource > self
26
+ require path / "dm_authenticated_user"
27
+ extend(Merb::Authentication::Mixins::AuthenticatedUser::DMClassMethods)
28
+ elsif defined?(ActiveRecord) && ancestors.include?(ActiveRecord::Base)
29
+ require path / "ar_authenticated_user"
30
+ extend(Merb::Authentication::Mixins::AuthenticatedUser::ARClassMethods)
31
+ elsif defined?(Sequel) && ancestors.include?(Sequel::Model)
32
+ require path / "sq_authenticated_user"
33
+ extend(Merb::Authentication::Mixins::AuthenticatedUser::SQClassMethods)
34
+ end
35
+
36
+ end # base.class_eval
37
+ end # self.included
38
+
39
+
40
+ module ClassMethods
41
+ def secure_digest(*args)
42
+ Digest::SHA1.hexdigest(args.flatten.join('--'))
43
+ end
44
+
45
+ # Create random key.
46
+ #
47
+ # ==== Returns
48
+ # String:: The generated key
49
+ def make_token
50
+ secure_digest(Time.now, (1..10).map{ rand.to_s })
51
+ end
52
+ end # ClassMethods
53
+
54
+ module InstanceMethods
55
+ def remember_token?
56
+ (!remember_token.blank?) &&
57
+ remember_token_expires_at && (Time.now.utc < remember_token_expires_at.to_time)
58
+ end
59
+
60
+ # These create and unset the fields required for remembering users between browser closes
61
+ def remember_me(time = 2.weeks)
62
+ remember_me_for time
63
+ end
64
+
65
+ def remember_me_for(time)
66
+ remember_me_until time.from_now.utc
67
+ end
68
+
69
+ def remember_me_until(time)
70
+ self.remember_token_expires_at = time
71
+ self.remember_token = self.class.make_token
72
+ save
73
+ end
74
+
75
+ # refresh token (keeping same expires_at) if it exists
76
+ def refresh_token
77
+ if remember_token?
78
+ self.remember_token = self.class.make_token
79
+ save
80
+ end
81
+ end
82
+
83
+ #
84
+ # Deletes the server-side record of the authentication token. The
85
+ # client-side (browser cookie) and server-side (this remember_token) must
86
+ # always be deleted together.
87
+ #
88
+ def forget_me
89
+ self.remember_token_expires_at = nil
90
+ self.remember_token = nil
91
+ save
92
+ end
93
+ end # InstanceMethods
94
+ end # AuthenticatedUser
95
+ end # Mixins
96
+ end # Authentication
97
+ end # Merb
@@ -0,0 +1,17 @@
1
+ module Merb
2
+ class Authentication
3
+ module Mixins
4
+ module AuthenticatedUser
5
+ module DMClassMethods
6
+ def self.extended(base)
7
+ base.class_eval do
8
+ property :remember_token_expires_at, DateTime
9
+ property :remember_token, String
10
+ end # base.class_eval
11
+
12
+ end # self.extended
13
+ end # DMClassMethods
14
+ end # AuthenticatedUser
15
+ end # Mixins
16
+ end # Authentication
17
+ end #Merb
@@ -0,0 +1,55 @@
1
+ class RememberMe < Merb::Authentication::Strategy
2
+ def run!
3
+ login_from_cookie
4
+ end
5
+
6
+ def current_user
7
+ @current_user
8
+ end
9
+
10
+ def current_user=(new_user)
11
+ @current_user = new_user
12
+ end
13
+
14
+ # Called from #current_user. Finaly, attempt to login by an expiring token in the cookie.
15
+ # for the paranoid: we _should_ be storing user_token = hash(cookie_token, request IP)
16
+ def login_from_cookie
17
+ current_user = cookies[:auth_token] && Merb::Authentication.user_class.first(:conditions => ["remember_token = ?", cookies[:auth_token]])
18
+ if current_user && current_user.remember_token?
19
+ handle_remember_cookie! false # freshen cookie token (keeping date)
20
+ current_user
21
+ end
22
+ end
23
+
24
+ #
25
+ # Remember_me Tokens
26
+ #
27
+ # Cookies shouldn't be allowed to persist past their freshness date,
28
+ # and they should be changed at each login
29
+
30
+ # Cookies shouldn't be allowed to persist past their freshness date,
31
+ # and they should be changed at each login
32
+
33
+ def valid_remember_cookie?
34
+ return nil unless current_user
35
+ (current_user.remember_token?) &&
36
+ (cookies[:auth_token] == current_user.remember_token)
37
+ end
38
+
39
+ # Refresh the cookie auth token if it exists, create it otherwise
40
+ def handle_remember_cookie! new_cookie_flag
41
+ return unless current_user
42
+ case
43
+ when valid_remember_cookie? then current_user.refresh_token # keeping same expiry date
44
+ when new_cookie_flag then current_user.remember_me
45
+ else current_user.forget_me
46
+ end
47
+ send_remember_cookie!
48
+ end
49
+
50
+ def send_remember_cookie!
51
+ cookies.set_cookie(:auth_token, current_user.remember_token, :expires => current_user.remember_token_expires_at.to_time)
52
+ end
53
+
54
+
55
+ end
@@ -0,0 +1,107 @@
1
+ if defined?(Merb::Plugins)
2
+
3
+ $:.unshift File.dirname(__FILE__)
4
+
5
+ dependency 'merb-mailer'
6
+ dependency 'merb-slices', :immediate => true
7
+ dependency 'merb-auth-core'
8
+ dependency 'merb-auth-more'
9
+ require(File.expand_path(File.dirname(__FILE__) / "merb_auth_slice_multisite" / "mixins") / "user_belongs_to_site")
10
+ require(File.expand_path(File.dirname(__FILE__) / "merb-auth-remember-me" / "mixins") / "authenticated_user")
11
+
12
+ Merb::Plugins.add_rakefiles "merb_auth_slice_multisite/merbtasks", "merb_auth_slice_multisite/slicetasks", "merb_auth_slice_multisite/spectasks"
13
+
14
+ # Register the Slice for the current host application
15
+ Merb::Slices::register(__FILE__)
16
+
17
+ # Slice configuration - set this in a before_app_loads callback.
18
+ # By default a Slice uses its own layout, so you can swicht to
19
+ # the main application layout or no layout at all if needed.
20
+ #
21
+ # Configuration options:
22
+ # :layout - the layout to use; defaults to :merb_auth_slice_multisite
23
+ # :mirror - which path component types to use on copy operations; defaults to all
24
+ Merb::Slices::config[:merb_auth_slice_multisite][:layout] ||= :application
25
+
26
+ # All Slice code is expected to be namespaced inside a module
27
+ module MerbAuthSliceMultisite
28
+
29
+ # Slice metadata
30
+ self.description = "see gem description"
31
+ self.version = "see gem version"
32
+ self.author = "see gem authors"
33
+
34
+ # Stub classes loaded hook - runs before LoadClasses BootLoader
35
+ # right after a slice's classes have been loaded internally.
36
+ def self.loaded
37
+ end
38
+
39
+ # Initialization hook - runs before AfterAppLoads BootLoader
40
+ def self.init
41
+ require 'merb-auth-more/mixins/redirect_back'
42
+ unless MerbAuthSliceMultisite[:no_default_strategies]
43
+ # Register the custom strategy so that this slice may utilize it
44
+ # from http://github.com/wycats/merb/blob/784ac7d71780d1a7cfb9152ba4cb0
45
+ # e18a990ab7a/merb-auth/merb-auth-more/lib/merb-auth-more.rb
46
+ merb_auth_more_path = File.expand_path(File.dirname(__FILE__)) / "merb-auth-more" / "strategies" / "multisite"
47
+ merb_auth_remember_me_path = File.expand_path(File.dirname(__FILE__)) / "merb-auth-remember-me" / "strategies"
48
+ Merb::Authentication.register(:multisite_password_form, merb_auth_more_path / "multisite_password_form.rb")
49
+ Merb::Authentication.register(:remember_me, merb_auth_remember_me_path / "remember_me.rb")
50
+ # activate the strategies
51
+ ::Merb::Authentication.activate!(:multisite_password_form)
52
+ ::Merb::Authentication.activate!(:remember_me)
53
+
54
+ Merb::Authentication.after_authentication do |user,request,params|
55
+ if params[:remember_me] == "1"
56
+ user.remember_me
57
+ request.cookies.set_cookie(:auth_token, user.remember_token, :expires => user.remember_token_expires_at.to_time)
58
+ end
59
+ user
60
+ end # Merb::Authentication.after_authentication
61
+ end
62
+ end
63
+
64
+ # Activation hook - runs after AfterAppLoads BootLoader
65
+ def self.activate
66
+ end
67
+
68
+ # Deactivation hook - triggered by Merb::Slices.deactivate(MerbAuthSliceMultisite)
69
+ def self.deactivate
70
+ end
71
+
72
+ # Setup routes inside the host application
73
+ #
74
+ # @param scope<Merb::Router::Behaviour>
75
+ # Routes will be added within this scope (namespace). In fact, any
76
+ # router behaviour is a valid namespace, so you can attach
77
+ # routes at any level of your router setup.
78
+ #
79
+ # @note prefix your named routes with :merb_auth_slice_multisite_
80
+ # to avoid potential conflicts with global named routes.
81
+ def self.setup_router(scope)
82
+ scope.match("/send_password", :method => :post).to(:controller => "passwords", :action => "send_password").name(:send_password)
83
+ scope.match("/login", :method => :get ).to(:controller => "/exceptions", :action => "unauthenticated").name(:login)
84
+ scope.match("/login", :method => :put ).to(:controller => "sessions", :action => "update").name(:perform_login)
85
+ scope.match("/logout").to(:controller => "sessions", :action => "destroy").name(:logout)
86
+ end
87
+
88
+ end
89
+
90
+ # Setup the slice layout for MerbAuthSliceMultisite
91
+ #
92
+ # Use MerbAuthSliceMultisite.push_path and MerbAuthSliceMultisite.push_app_path
93
+ # to set paths to merb_auth_slice_multisite-level and app-level paths. Example:
94
+ #
95
+ # MerbAuthSliceMultisite.push_path(:application, MerbAuthSliceMultisite.root)
96
+ # MerbAuthSliceMultisite.push_app_path(:application, Merb.root / 'slices' / 'merb_auth_slice_multisite')
97
+ # ...
98
+ #
99
+ # Any component path that hasn't been set will default to MerbAuthSliceMultisite.root
100
+ #
101
+ # Or just call setup_default_structure! to setup a basic Merb MVC structure.
102
+ MerbAuthSliceMultisite.setup_default_structure!
103
+
104
+ # Add dependencies for other MerbAuthSliceMultisite classes below. Example:
105
+ # dependency "merb_auth_slice_multisite/other"
106
+
107
+ end