authlogic_crowd 0.2.4 → 0.3.0.pre.2

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/.document CHANGED
@@ -1,5 +1,5 @@
1
- README.rdoc
2
- lib/**/*.rb
3
- bin/*
4
- features/**/*.feature
5
- LICENSE
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
data/Gemfile CHANGED
@@ -2,3 +2,6 @@ source "http://rubygems.org"
2
2
 
3
3
  # Specify your gem's dependencies in authlogic_crowd.gemspec
4
4
  gemspec
5
+
6
+ group :test do
7
+ end
data/README.markdown ADDED
@@ -0,0 +1,173 @@
1
+ Authlogic Crowd
2
+ ===============
3
+
4
+ Authlogic Crowd is an extension of the Authlogic library to add Atlassian Crowd
5
+ support. We have only tested this plugin with Authlogic 2.x and Rails 2.x.
6
+
7
+
8
+ ## Installation
9
+
10
+ Add the gem to your Gemfile:
11
+
12
+ gem 'authlogic_crowd'
13
+
14
+ and run `bundle`.
15
+
16
+
17
+ ## Configuration
18
+
19
+ In your model class, add Crowd configuration:
20
+
21
+ class User < ActiveRecord::Base
22
+ acts_as_authentic do |c|
23
+ c.crowd_service_url = "http://mycrowdapp:8095/crowd"
24
+ c.crowd_app_name = "testapp"
25
+ c.crowd_app_password = "testpass"
26
+ end
27
+ end
28
+
29
+
30
+ ## Usage
31
+
32
+ When a user logs in via your existing login form, the user's credentials will
33
+ be authenticated with Crowd. authlogic_crowd will also authenticate users with
34
+ an existing Crowd token_key cookie.
35
+
36
+ authlogic_crowd acts as an *additional* authentication plugin. Other
37
+ authentication plugins will be tried in the order in which they were
38
+ registered. Thus, if your model contains password fields used by the
39
+ built-in `Password` authentication module, Authlogic will attempt to
40
+ authenticate via local passwords first. If this fails, it will move on to
41
+ authenticate via Crowd. If you want to skip internal password checking, you
42
+ should set internal password fields to `nil`.
43
+
44
+
45
+ ### Re-authenticate Every x Seconds
46
+
47
+ By default, authlogic_crowd authenticates the Crowd token key cookie on every
48
+ request. You can tell the module to cache authentication and only
49
+ re-authenticate periodically using *crowd_auth_every*:
50
+
51
+ class UserSession < Authlogic::Session::Base
52
+ crowd_auth_every 10.minutes
53
+ end
54
+
55
+
56
+ ### Auto Registration
57
+
58
+ When a Crowd user logs in with no corresponding local user, a new local user
59
+ will be added by default. You can disable auto-registration with the
60
+ `auto_register` setting in your Authlogic session:
61
+
62
+ class UserSession < Authlogic::Session::Base
63
+ auto_register false
64
+ end
65
+
66
+
67
+ ### Auto Add Crowd Records
68
+
69
+ When a new local user is added, authlogic_crowd can add a corresponding user to
70
+ Crowd. This is disabled by default. To enable, use the `add_crowd_records`
71
+ setting:
72
+
73
+ class User < ActiveRecord::Base
74
+ acts_as_authentic do |c|
75
+ c.add_crowd_records = true
76
+ end
77
+ end
78
+
79
+
80
+ ### Auto Update Crowd Records
81
+
82
+ When a local user is updated, authlogic_crowd will update the corresponding
83
+ Crowd user. This is enabled by default. To disable, use the
84
+ `update_crowd_records` setting:
85
+
86
+ class User < ActiveRecord::Base
87
+ acts_as_authentic do |c|
88
+ c.update_crowd_records = false
89
+ end
90
+ end
91
+
92
+
93
+ ### Disable Crowd
94
+
95
+ If you need to disable Crowd (in testing for example), use the `crowd_enabled`
96
+ setting:
97
+
98
+ class User < ActiveRecord::Base
99
+ acts_as_authentic do |c|
100
+ c.crowd_enabled = false
101
+ end
102
+ end
103
+
104
+
105
+ ## Callbacks
106
+
107
+ authlogic_crowd adds several callbacks that can be used to customize the
108
+ plugin. Callbacks execute in the following order:
109
+
110
+ before_create_from_crowd
111
+ before_sync_from_crowd
112
+ sync_from_crowd
113
+ after_sync_from_crowd
114
+ after_create_from_crowd
115
+
116
+ before_create_crowd_record
117
+ before_sync_to_crowd
118
+ sync_to_crowd
119
+ after_sync_to_crowd
120
+ after_create_crowd_record
121
+
122
+
123
+ ### before_sync_from_crowd, sync_from_crowd, after_sync_from_crowd
124
+
125
+ Called whenever a local record should be synchronized from Crowd. Each time a
126
+ user logs in to your application via Crowd (with login credentials or the
127
+ token_key cookie), the local user record is synchronized with the Crowd record.
128
+
129
+ For example:
130
+
131
+ class User < ActiveRecord::Base
132
+ acts_as_authentic do |c|
133
+ c.sync_from_crowd :update_from_crowd_record
134
+ end
135
+
136
+ def update_from_crowd_record
137
+ self.email = self.crowd_record.email
138
+ self.name = self.crowd_record.first_name + ' ' + self.crowd_record.last_name
139
+ end
140
+ end
141
+
142
+
143
+ ### before_sync_to_crowd, sync_to_crowd, after_sync_to_crowd
144
+
145
+ Called whenever Crowd should be synchornized from a local record.
146
+
147
+ For example:
148
+
149
+ class User < ActiveRecord::Base
150
+ acts_as_authentic do |c|
151
+ c.sync_to_crowd :update_crowd_record
152
+ end
153
+
154
+ def update_crowd_record
155
+ self.crowd_record = self.email
156
+ self.crowd_record.display_name = self.name
157
+ self.crowd_record.first_name = self.first_name
158
+ self.crowd_record.last_name = self.last_name
159
+ end
160
+ end
161
+
162
+
163
+ ### before_create_from_crowd, after_create_from_crowd
164
+
165
+ Called when creating a new local record from a crowd record. When
166
+ auto-registration is enabled new local users will be created automatically
167
+ when existing Crowd users log in to your application.
168
+
169
+
170
+ ### before_create_crowd_record, after_create_crowd_record
171
+
172
+ Called when creating a new crowd record from a new local record. These
173
+ callbacks are only executed if the `add_crowd_records` setting is enabled.
data/Rakefile CHANGED
@@ -1,21 +1 @@
1
- require 'rake'
2
- require 'rake/testtask'
3
- require 'rake/rdoctask'
4
- require 'bundler'
5
- Bundler::GemHelper.install_tasks
6
-
7
- desc 'Run tests for InheritedResources.'
8
- Rake::TestTask.new(:test) do |t|
9
- t.pattern = 'test/**/*_test.rb'
10
- t.verbose = true
11
- end
12
-
13
- desc 'Generate documentation for InheritedResources.'
14
- Rake::RDocTask.new(:rdoc) do |rdoc|
15
- rdoc.rdoc_dir = 'rdoc'
16
- rdoc.title = 'InheritedResources'
17
- rdoc.options << '--line-numbers' << '--inline-source'
18
- rdoc.rdoc_files.include('README.rdoc')
19
- rdoc.rdoc_files.include('lib/**/*.rb')
20
- end
21
-
1
+ require 'bundler/gem_tasks'
@@ -1,47 +1,27 @@
1
+ # -*- encoding: utf-8 -*-
1
2
  $:.push File.expand_path("../lib",__FILE__)
2
3
  require 'authlogic_crowd/version'
3
4
 
4
5
  Gem::Specification.new do |s|
5
- s.name = %q{authlogic_crowd}
6
- s.version = AuthlogicCrowd::VERSION.dup
7
- s.platform = Gem::Platform::RUBY
8
- s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
9
- s.authors = ["Paul Strong"]
10
- s.description = %q{Authlogic Crowd}
11
- s.email = %q{paul@thestrongfamily.org}
12
- s.extra_rdoc_files = [
13
- "README.rdoc"
14
- ]
15
- s.files = %w(
16
- .document
17
- .gitignore
18
- Gemfile
19
- README.rdoc
20
- Rakefile
21
- authlogic_crowd.gemspec
22
- lib/authlogic_crowd.rb
23
- lib/authlogic_crowd/acts_as_authentic.rb
24
- lib/authlogic_crowd/acts_as_authentic_callbacks.rb
25
- lib/authlogic_crowd/session.rb
26
- lib/authlogic_crowd/session_callbacks.rb
27
- lib/authlogic_crowd/version.rb
28
- test/helper.rb
29
- test/test_authlogic_crowd.rb
30
- )
31
- s.test_files = %w(
32
- test/helper.rb
33
- test/test_authlogic_crowd.rb
34
- )
35
- s.homepage = %q{http://github.com/thinkwell/authlogic_crowd}
6
+ s.name = %q{authlogic_crowd}
7
+ s.version = AuthlogicCrowd::VERSION.dup
8
+ s.authors = ["Paul Strong"]
9
+ s.email = %q{paul@thestrongfamily.org}
10
+ s.homepage = %q{http://github.com/thinkwell/authlogic_crowd}
11
+ s.summary = %q{Atlassian Crowd support for Authlogic}
12
+ s.description = %q{Atlassian Crowd support for Authlogic}
13
+
14
+ s.rubyforge_project = "authlogic_crowd"
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
36
19
  s.require_paths = ["lib"]
37
- s.rubygems_version = %q{1.3.7}
38
- s.summary = %q{Atlassian Crowd support for Authlogic}
39
20
 
40
- s.add_development_dependency(%q<thoughtbot-shoulda>, [">= 0"])
41
- s.add_development_dependency(%q<fcoury-matchy>, [">= 0"])
42
- s.add_development_dependency(%q<rr>, [">= 0"])
43
21
  s.add_runtime_dependency(%q<authlogic>, [">= 2.1.3", "< 3.0.0"])
44
- s.add_runtime_dependency(%q<simple_crowd>, [">= 1.0.0"])
22
+ s.add_runtime_dependency(%q<simple_crowd>, [">= 1.1.0"])
45
23
 
24
+ s.add_development_dependency(%q<bundler>, [">= 1.0.21"])
25
+ s.add_development_dependency(%q<rake>, [">= 0"])
46
26
  end
47
27
 
@@ -1,9 +1,8 @@
1
- require "authlogic_crowd/acts_as_authentic"
2
- require "authlogic_crowd/session"
3
- require "authlogic_crowd/session_callbacks"
4
- require "authlogic_crowd/acts_as_authentic_callbacks"
5
-
6
- ActiveRecord::Base.send(:include, AuthlogicCrowd::ActsAsAuthentic)
7
- ActiveRecord::Base.send(:include, AuthlogicCrowd::ActsAsAuthenticCallbacks)
8
- Authlogic::Session::Base.send(:include, AuthlogicCrowd::Session)
9
- Authlogic::Session::Base.send(:include, AuthlogicCrowd::SessionCallbacks)
1
+ require "simple_crowd"
2
+ require "authlogic_crowd/acts_as_authentic"
3
+ require "authlogic_crowd/session"
4
+ require "authlogic_crowd/acts_as_authentic_callbacks"
5
+ require "authlogic_crowd/crowd_synchronizer"
6
+
7
+ ActiveRecord::Base.send(:include, AuthlogicCrowd::ActsAsAuthentic)
8
+ Authlogic::Session::Base.send(:include, AuthlogicCrowd::Session)
@@ -1,138 +1,185 @@
1
- module AuthlogicCrowd
2
- module ActsAsAuthentic
3
- # Adds in the neccesary modules for acts_as_authentic to include and also disabled password validation if
4
- # OpenID is being used.
5
- def self.included(klass)
6
- klass.class_eval do
7
- extend Config
8
- add_acts_as_authentic_module(Methods, :prepend)
9
- end
10
- end
11
- module Config
12
-
13
- # **REQUIRED**
14
- #
15
- # Specify your crowd service url.
16
- # @param [String] url to use when calling Crowd
17
- def crowd_service_url(url=nil)
18
- rw_config(:crowd_service_url, url, "http://localhost:8095/crowd/services/SecurityServer")
19
- end
20
- alias_method :crowd_service_url=, :crowd_service_url
21
-
22
- # **REQUIRED**
23
- #
24
- # Specify your crowd app name.
25
- # @param [String] name of app to use when calling Crowd
26
- def crowd_app_name(name=nil)
27
- rw_config(:crowd_app_name, name, nil)
28
- end
29
- alias_method :crowd_app_name=, :crowd_app_name
30
-
31
- # **REQUIRED**
32
- #
33
- # Specify your crowd app password.
34
- # @param [String] password Plain-text password for crowd app validation
35
- def crowd_app_password(password=nil)
36
- rw_config(:crowd_app_password, password, nil)
37
- end
38
- alias_method :crowd_app_password=, :crowd_app_password
39
-
40
- def crowd_user_token_field(value = nil)
41
- rw_config(:crowd_user_token_field, value, :crowd_user_token)
42
- end
43
- alias_method :crowd_user_token_field=, :crowd_user_token_field
44
-
45
- def crowd_enabled(value=nil)
46
- rw_config(:crowd_enabled, value, true)
47
- end
48
-
49
- end
50
- module Methods
51
- def self.included(klass)
52
- klass.class_eval do
53
- validate_on_create :must_have_unique_crowd_login, :if => :using_crowd?, :unless => :crowd_record
54
-
55
- # TODO: Cleanup and refactor into callbacks
56
- def create
57
- if using_crowd? && !crowd_record
58
- crowd_user = self.create_crowd_user
59
- if crowd_user
60
- # Crowd is going to store password so clear them from local object
61
- self.clear_passwords
62
- result = super
63
- # Delete crowd user if local creation failed
64
- crowd_client.delete_user crowd_user.user unless result
65
- if result
66
- user_token = crowd_client.create_user_token crowd_user.username
67
- session_class.crowd_user_token = user_token unless
68
- session_class.controller && session_class.controller.session[:"crowd.token_key"]
69
- end
70
- return result
71
- end
72
- end
73
- super
74
- end
75
- validates_length_of_password_field_options validates_length_of_password_field_options.merge(:on => :create)
76
- validates_confirmation_of_password_field_options validates_confirmation_of_password_field_options.merge(:on => :create)
77
- validates_length_of_password_confirmation_field_options validates_length_of_password_confirmation_field_options.merge(:on => :create)
78
- end
79
- end
80
-
81
- attr_accessor :crowd_record
82
-
83
- protected
84
-
85
- def create_crowd_user
86
- return unless self.login && @password
87
- self.crowd_record = SimpleCrowd::User.new({:username => self.login})
88
- sync_on_create
89
- crowd_client.add_user self.crowd_record, @password
90
- end
91
-
92
- def clear_passwords
93
- @password = nil
94
- @password_changed = false
95
- send("#{self.class.crypted_password_field}=", nil) if self.class.crypted_password_field
96
- send("#{self.class.password_salt_field}=", nil) if self.class.password_salt_field
97
- end
98
-
99
- private
100
-
101
- def must_have_unique_crowd_login
102
- login = send(self.class.login_field)
103
- crowd_user = crowd_client.find_user_by_name(login)
104
- errors.add(self.class.login_field, "is already taken") unless crowd_user.nil? || !errors.on(self.class.login_field).nil?
105
- end
106
-
107
- def crowd_client
108
- @crowd_client ||= SimpleCrowd::Client.new(crowd_config)
109
- end
110
- def load_crowd_app_token
111
- cached_token = Rails.cache.read('crowd_app_token')
112
- crowd_client.app_token = cached_token unless cached_token.nil?
113
- Rails.cache.write('crowd_app_token', crowd_client.app_token) unless cached_token == crowd_client.app_token
114
- end
115
- def crowd_cookie_info
116
- unless @crowd_cookie_info
117
- cached_info = Rails.cache.read('crowd_cookie_info')
118
- @crowd_cookie_info ||= cached_info || crowd_client.get_cookie_info
119
- Rails.cache.write('crowd_cookie_info', @crowd_cookie_info) unless cached_info == @crowd_cookie_info
120
- end
121
- @crowd_cookie_info
122
- end
123
- def crowd_config
124
- {:service_url => self.class.crowd_service_url,
125
- :app_name => self.class.crowd_app_name,
126
- :app_password => self.class.crowd_app_password}
127
- end
128
-
129
- def using_crowd?
130
- self.class.crowd_enabled && !(self.class.crowd_app_name.nil? || self.class.crowd_app_password.nil? || self.class.crowd_service_url.nil?)
131
- end
132
-
133
- def validate_password_with_crowd?
134
- #!using_crowd? && require_password?
135
- end
136
- end
137
- end
138
- end
1
+ module AuthlogicCrowd
2
+ module ActsAsAuthentic
3
+ # Adds in the neccesary modules for acts_as_authentic to include and also disabled password validation if
4
+ # Crowd is being used.
5
+ def self.included(klass)
6
+ klass.class_eval do
7
+ extend Config
8
+ add_acts_as_authentic_module(ActsAsAuthenticCallbacks)
9
+ add_acts_as_authentic_module(Methods)
10
+ end
11
+ end
12
+
13
+ module Config
14
+ # **REQUIRED**
15
+ #
16
+ # Specify your crowd service url.
17
+ # @param [String] url to use when calling Crowd
18
+ def crowd_service_url(url=nil)
19
+ rw_config(:crowd_service_url, url, "http://localhost:8095/crowd/services/SecurityServer")
20
+ end
21
+ alias_method :crowd_service_url=, :crowd_service_url
22
+
23
+ # **REQUIRED**
24
+ #
25
+ # Specify your crowd app name.
26
+ # @param [String] name of app to use when calling Crowd
27
+ def crowd_app_name(name=nil)
28
+ rw_config(:crowd_app_name, name, nil)
29
+ end
30
+ alias_method :crowd_app_name=, :crowd_app_name
31
+
32
+ # **REQUIRED**
33
+ #
34
+ # Specify your crowd app password.
35
+ # @param [String] password Plain-text password for crowd app validation
36
+ def crowd_app_password(password=nil)
37
+ rw_config(:crowd_app_password, password, nil)
38
+ end
39
+ alias_method :crowd_app_password=, :crowd_app_password
40
+
41
+ # Should new local records be added to crowd?
42
+ # Default is false.
43
+ def add_crowd_records(value=nil)
44
+ rw_config(:add_crowd_records, value, false)
45
+ end
46
+ alias_method :add_crowd_records=, :add_crowd_records
47
+
48
+ # Should changes to local records be synced to crowd?
49
+ # Default is true
50
+ def update_crowd_records(value=nil)
51
+ rw_config(:update_crowd_records, value, true)
52
+ end
53
+ alias_method :update_crowd_records=, :update_crowd_records
54
+
55
+ def crowd_enabled(value=nil)
56
+ rw_config(:crowd_enabled, value, true)
57
+ end
58
+ alias_method :crowd_enabled=, :crowd_enabled
59
+ end
60
+
61
+ module ClassMethods
62
+ def crowd_config
63
+ {
64
+ :service_url => crowd_service_url,
65
+ :app_name => crowd_app_name,
66
+ :app_password => crowd_app_password,
67
+ :cache_store => Rails.cache,
68
+ }
69
+ end
70
+
71
+ def crowd_client
72
+ SimpleCrowd::Client.new(crowd_config)
73
+ end
74
+
75
+ def crowd_synchronizer(crowd_client=self.crowd_client, local_record=nil)
76
+ CrowdSynchronizer.new(self, crowd_client, local_record)
77
+ end
78
+
79
+ def crowd_enabled?
80
+ !!self.crowd_enabled
81
+ end
82
+
83
+ def using_crowd?
84
+ self.crowd_enabled? && !(self.crowd_app_name.nil? || self.crowd_app_password.nil? || self.crowd_service_url.nil?)
85
+ end
86
+ end
87
+
88
+ module Methods
89
+ def self.included(klass)
90
+ klass.class_eval do
91
+ extend ClassMethods
92
+
93
+ after_create(:if => [:using_crowd?, :adding_crowd_records?], :unless => :has_crowd_record?) do |r|
94
+ r.crowd_synchronizer.create_crowd_record
95
+ end
96
+
97
+ before_update :crowd_before_update_reset_password, :if => [:using_crowd?, :updating_crowd_records?, :has_crowd_record?]
98
+
99
+ after_update(:if => [:using_crowd?, :updating_crowd_records?, :has_crowd_record?]) do |r|
100
+ r.crowd_synchronizer.sync_to_crowd
101
+ end
102
+
103
+ validate_on_create :must_have_unique_crowd_login, :if => [:using_crowd?, :adding_crowd_records?], :unless => :has_crowd_record?
104
+ end
105
+ end
106
+
107
+ attr_accessor :crowd_record, :crowd_synchronizer
108
+
109
+ def crowd_client
110
+ @crowd_client ||= self.class.crowd_client
111
+ end
112
+
113
+ def crowd_synchronizer
114
+ @crowd_synchronizer ||= self.class.crowd_synchronizer(crowd_client, self)
115
+ end
116
+
117
+ def crowd_record
118
+ return nil unless using_crowd?
119
+ if @crowd_record.nil?
120
+ @crowd_record = false
121
+ begin
122
+ login = self.send(self.class.login_field)
123
+ record = crowd_client.find_user_by_name(login)
124
+ @crowd_record = record if record
125
+ rescue SimpleCrowd::CrowdError => e
126
+ Rails.logger.warn "CROWD[#{__method__}]: Unexpected error. #{e}"
127
+ end
128
+ end
129
+ @crowd_record == false ? nil : @crowd_record
130
+ end
131
+
132
+ def using_crowd?
133
+ self.class.using_crowd?
134
+ end
135
+
136
+ def adding_crowd_records?
137
+ self.class.add_crowd_records
138
+ end
139
+
140
+ def updating_crowd_records?
141
+ self.class.update_crowd_records
142
+ end
143
+
144
+ def has_crowd_record?
145
+ !!self.crowd_record
146
+ end
147
+
148
+ def crowd_password
149
+ password
150
+ end
151
+
152
+ def crowd_password_changed?
153
+ password_changed?
154
+ end
155
+
156
+ def valid_crowd_password?(plaintext_password)
157
+ if using_crowd?
158
+ begin
159
+ token = crowd_client.authenticate_user(self.unique_id, plaintext_password)
160
+ return true if token
161
+ rescue SimpleCrowd::CrowdError => e
162
+ Rails.logger.warn "CROWD[#{__method__}]: Unexpected error. #{e}"
163
+ end
164
+ end
165
+ false
166
+ end
167
+
168
+
169
+ private
170
+
171
+ def must_have_unique_crowd_login
172
+ login = send(self.class.login_field)
173
+ crowd_user = crowd_client.find_user_by_name(login)
174
+ errors.add(self.class.login_field, "is already taken") unless crowd_user.nil? || !errors.on(self.class.login_field).nil?
175
+ end
176
+
177
+ def crowd_before_update_reset_password
178
+ if crowd_password_changed?
179
+ send("#{password_salt_field}=", nil) if password_salt_field
180
+ send("#{crypted_password_field}=", nil)
181
+ end
182
+ end
183
+ end
184
+ end
185
+ end