authlogic_crowd 0.2.4 → 0.3.0.pre.2

Sign up to get free protection for your applications and to get access to all the features.
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