authlogic_crowd 0.2.3
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 +5 -0
- data/.gitignore +26 -0
- data/Gemfile +4 -0
- data/README.rdoc +14 -0
- data/Rakefile +21 -0
- data/authlogic_crowd.gemspec +47 -0
- data/lib/authlogic_crowd/acts_as_authentic.rb +134 -0
- data/lib/authlogic_crowd/acts_as_authentic_callbacks.rb +26 -0
- data/lib/authlogic_crowd/session.rb +285 -0
- data/lib/authlogic_crowd/session_callbacks.rb +19 -0
- data/lib/authlogic_crowd/version.rb +3 -0
- data/lib/authlogic_crowd.rb +9 -0
- data/test/helper.rb +13 -0
- data/test/test_authlogic_crowd.rb +7 -0
- metadata +162 -0
data/.document
ADDED
data/.gitignore
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
## MAC OS
|
|
2
|
+
.DS_Store
|
|
3
|
+
|
|
4
|
+
## TEXTMATE
|
|
5
|
+
*.tmproj
|
|
6
|
+
tmtags
|
|
7
|
+
|
|
8
|
+
## EMACS
|
|
9
|
+
*~
|
|
10
|
+
\#*
|
|
11
|
+
.\#*
|
|
12
|
+
|
|
13
|
+
## VIM
|
|
14
|
+
*.swp
|
|
15
|
+
|
|
16
|
+
## PROJECT::GENERAL
|
|
17
|
+
coverage
|
|
18
|
+
rdoc
|
|
19
|
+
doc
|
|
20
|
+
pkg
|
|
21
|
+
.bundle
|
|
22
|
+
.idea
|
|
23
|
+
.yardoc
|
|
24
|
+
|
|
25
|
+
## PROJECT::SPECIFIC
|
|
26
|
+
Gemfile.lock
|
data/Gemfile
ADDED
data/README.rdoc
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
= authlogic_crowd
|
|
2
|
+
|
|
3
|
+
Incomplete Authlogic plugin for Atlassian Crowd ( do not use )
|
|
4
|
+
Description goes here.
|
|
5
|
+
|
|
6
|
+
== Note on Patches/Pull Requests
|
|
7
|
+
|
|
8
|
+
* Fork the project.
|
|
9
|
+
* Make your feature addition or bug fix.
|
|
10
|
+
* Add tests for it. This is important so I don't break it in a
|
|
11
|
+
future version unintentionally.
|
|
12
|
+
* Commit, do not mess with rakefile, version, or history.
|
|
13
|
+
(if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
|
|
14
|
+
* Send me a pull request. Bonus points for topic branches.
|
data/Rakefile
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
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
|
+
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
$:.push File.expand_path("../lib",__FILE__)
|
|
2
|
+
require 'authlogic_crowd/version'
|
|
3
|
+
|
|
4
|
+
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/lapluviosilla/authlogic_crowd}
|
|
36
|
+
s.require_paths = ["lib"]
|
|
37
|
+
s.rubygems_version = %q{1.3.7}
|
|
38
|
+
s.summary = %q{Atlassian Crowd support for Authlogic}
|
|
39
|
+
|
|
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
|
+
s.add_runtime_dependency(%q<authlogic>, [">= 2.1.3", "< 3.0.0"])
|
|
44
|
+
s.add_runtime_dependency(%q<simple_crowd>, [">= 1.0.0"])
|
|
45
|
+
|
|
46
|
+
end
|
|
47
|
+
|
|
@@ -0,0 +1,134 @@
|
|
|
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
|
+
end
|
|
46
|
+
module Methods
|
|
47
|
+
def self.included(klass)
|
|
48
|
+
klass.class_eval do
|
|
49
|
+
validate_on_create :must_have_unique_crowd_login
|
|
50
|
+
|
|
51
|
+
# TODO: Cleanup and refactor into callbacks
|
|
52
|
+
def create
|
|
53
|
+
if using_crowd? && !crowd_record
|
|
54
|
+
crowd_user = self.create_crowd_user
|
|
55
|
+
if crowd_user
|
|
56
|
+
# Crowd is going to store password so clear them from local object
|
|
57
|
+
self.clear_passwords
|
|
58
|
+
result = super
|
|
59
|
+
# Delete crowd user if local creation failed
|
|
60
|
+
crowd_client.delete_user crowd_user.user unless result
|
|
61
|
+
if result
|
|
62
|
+
user_token = crowd_client.create_user_token crowd_user.username
|
|
63
|
+
session_class.crowd_user_token = user_token unless
|
|
64
|
+
session_class.controller && session_class.controller.session[:"crowd.token_key"]
|
|
65
|
+
end
|
|
66
|
+
return result
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
super
|
|
70
|
+
end
|
|
71
|
+
validates_length_of_password_field_options validates_length_of_password_field_options.merge(:on => :create)
|
|
72
|
+
validates_confirmation_of_password_field_options validates_confirmation_of_password_field_options.merge(:on => :create)
|
|
73
|
+
validates_length_of_password_confirmation_field_options validates_length_of_password_confirmation_field_options.merge(:on => :create)
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
attr_accessor :crowd_record
|
|
78
|
+
|
|
79
|
+
protected
|
|
80
|
+
|
|
81
|
+
def create_crowd_user
|
|
82
|
+
return unless self.login && @password
|
|
83
|
+
self.crowd_record = SimpleCrowd::User.new({:username => self.login})
|
|
84
|
+
sync_on_create
|
|
85
|
+
crowd_client.add_user self.crowd_record, @password
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def clear_passwords
|
|
89
|
+
@password = nil
|
|
90
|
+
@password_changed = false
|
|
91
|
+
send("#{self.class.crypted_password_field}=", nil) if self.class.crypted_password_field
|
|
92
|
+
send("#{self.class.password_salt_field}=", nil) if self.class.password_salt_field
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
private
|
|
96
|
+
|
|
97
|
+
def must_have_unique_crowd_login
|
|
98
|
+
login = send(self.class.login_field)
|
|
99
|
+
crowd_user = crowd_client.find_user_by_name(login)
|
|
100
|
+
errors.add(self.class.login_field, "is already taken") unless crowd_user.nil? || !errors.on(self.class.login_field).nil?
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def crowd_client
|
|
104
|
+
@crowd_client ||= SimpleCrowd::Client.new(crowd_config)
|
|
105
|
+
end
|
|
106
|
+
def load_crowd_app_token
|
|
107
|
+
cached_token = Rails.cache.read('crowd_app_token')
|
|
108
|
+
crowd_client.app_token = cached_token unless cached_token.nil?
|
|
109
|
+
Rails.cache.write('crowd_app_token', crowd_client.app_token) unless cached_token == crowd_client.app_token
|
|
110
|
+
end
|
|
111
|
+
def crowd_cookie_info
|
|
112
|
+
unless @crowd_cookie_info
|
|
113
|
+
cached_info = Rails.cache.read('crowd_cookie_info')
|
|
114
|
+
@crowd_cookie_info ||= cached_info || crowd_client.get_cookie_info
|
|
115
|
+
Rails.cache.write('crowd_cookie_info', @crowd_cookie_info) unless cached_info == @crowd_cookie_info
|
|
116
|
+
end
|
|
117
|
+
@crowd_cookie_info
|
|
118
|
+
end
|
|
119
|
+
def crowd_config
|
|
120
|
+
{:service_url => self.class.crowd_service_url,
|
|
121
|
+
:app_name => self.class.crowd_app_name,
|
|
122
|
+
:app_password => self.class.crowd_app_password}
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def using_crowd?
|
|
126
|
+
!(self.class.crowd_app_name.nil? || self.class.crowd_app_password.nil? || self.class.crowd_service_url.nil?)
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def validate_password_with_crowd?
|
|
130
|
+
#!using_crowd? && require_password?
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
module AuthlogicCrowd
|
|
2
|
+
module ActsAsAuthenticCallbacks
|
|
3
|
+
def self.included(klass)
|
|
4
|
+
klass.class_eval do
|
|
5
|
+
add_acts_as_authentic_module(Methods, :prepend)
|
|
6
|
+
end
|
|
7
|
+
end
|
|
8
|
+
module Methods
|
|
9
|
+
METHODS = [
|
|
10
|
+
"sync_on_create"
|
|
11
|
+
]
|
|
12
|
+
def self.included(base)
|
|
13
|
+
base.send :include, ActiveSupport::Callbacks
|
|
14
|
+
base.define_callbacks *METHODS
|
|
15
|
+
end
|
|
16
|
+
private
|
|
17
|
+
METHODS.each do |method|
|
|
18
|
+
class_eval <<-"end_eval", __FILE__, __LINE__
|
|
19
|
+
def #{method}
|
|
20
|
+
run_callbacks(:#{method}) { |result, object| result == false }
|
|
21
|
+
end
|
|
22
|
+
end_eval
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
module AuthlogicCrowd
|
|
2
|
+
module Session
|
|
3
|
+
def self.included(klass)
|
|
4
|
+
klass.class_eval do
|
|
5
|
+
extend Config
|
|
6
|
+
include Methods
|
|
7
|
+
end
|
|
8
|
+
end
|
|
9
|
+
module Config
|
|
10
|
+
|
|
11
|
+
# Single Signout (defaults to true)
|
|
12
|
+
# @param [Boolean] value
|
|
13
|
+
def crowd_sso(value=nil)
|
|
14
|
+
rw_config(:crowd_sso, value, true)
|
|
15
|
+
end
|
|
16
|
+
alias_method :crowd_sso=, :crowd_sso
|
|
17
|
+
|
|
18
|
+
def crowd_sso?
|
|
19
|
+
crowd_sso
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Auto Register is enabled by default.
|
|
23
|
+
# Add this in your Session object if you need to disable auto-registration via crowd
|
|
24
|
+
def auto_register(value=true)
|
|
25
|
+
auto_register_value(value)
|
|
26
|
+
end
|
|
27
|
+
def auto_register_value(value=nil)
|
|
28
|
+
rw_config(:auto_register,value,true)
|
|
29
|
+
end
|
|
30
|
+
alias_method :auto_register=,:auto_register
|
|
31
|
+
|
|
32
|
+
def crowd_user_token= token
|
|
33
|
+
session_user_token = controller && controller.session[:"crowd.token_key"]
|
|
34
|
+
cookie_user_token = crowd_sso? && controller && controller.cookies[:"crowd.token_key"]
|
|
35
|
+
cached_info = Rails.cache.read('crowd_cookie_info')
|
|
36
|
+
@crowd_client ||= SimpleCrowd::Client.new({
|
|
37
|
+
:service_url => klass.crowd_service_url,
|
|
38
|
+
:app_name => klass.crowd_app_name,
|
|
39
|
+
:app_password => klass.crowd_app_password})
|
|
40
|
+
crowd_cookie_info ||= cached_info || @crowd_client.get_cookie_info
|
|
41
|
+
controller.session[:"crowd.token_key"] = token unless session_user_token == token || !controller
|
|
42
|
+
controller.cookies[:"crowd.token_key"] = {:domain => crowd_cookie_info[:domain],
|
|
43
|
+
:secure => crowd_cookie_info[:secure],
|
|
44
|
+
:value => token} unless cookie_user_token == token || !crowd_sso? || !controller
|
|
45
|
+
end
|
|
46
|
+
def crowd_user_token
|
|
47
|
+
controller && (controller.params["crowd.token_key"] || controller.cookies[:"crowd.token_key"] || controller.session[:"crowd.token_key"])
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
module Methods
|
|
51
|
+
def self.included(klass)
|
|
52
|
+
klass.class_eval do
|
|
53
|
+
attr_accessor :new_registration
|
|
54
|
+
validate :validate_by_crowd, :if => :authenticating_with_crowd?
|
|
55
|
+
persist :validate_by_crowd, :if => :authenticating_with_crowd?
|
|
56
|
+
after_create :sync_with_crowd, :if => :authenticating_with_crowd?
|
|
57
|
+
before_destroy :logout_of_crowd, :if => [:authenticating_with_crowd?, :sso?]
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# Temporary storage of crowd record for syncing purposes
|
|
62
|
+
attr_accessor :crowd_record
|
|
63
|
+
|
|
64
|
+
# Determines if the authenticated user is also a new registration.
|
|
65
|
+
# For use in the session controller to help direct the most appropriate action to follow.
|
|
66
|
+
def new_registration?
|
|
67
|
+
new_registration || !new_registration.nil?
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# Determines if the authenticated user has a complete registration (no validation errors)
|
|
71
|
+
# For use in the session controller to help direct the most appropriate action to follow.
|
|
72
|
+
def registration_complete?
|
|
73
|
+
attempted_record && attempted_record.valid?
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def auto_register?
|
|
77
|
+
self.class.auto_register_value
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
protected
|
|
81
|
+
|
|
82
|
+
# Determines whether to use crowd to authenticate and validate the current request
|
|
83
|
+
# For now we assume the app wants to use Crowd exclusively.
|
|
84
|
+
# Use crowd authentication if tokens are present or if login/password is available but not valid or is blank in db
|
|
85
|
+
# TODO: Add flexibility regarding multiple authentication methods and identity mapping
|
|
86
|
+
def authenticating_with_crowd?
|
|
87
|
+
errors.empty? &&
|
|
88
|
+
!klass.crowd_app_name.blank? &&
|
|
89
|
+
!klass.crowd_app_password.blank? &&
|
|
90
|
+
((login_field && (!send(login_field).nil? || !send("protected_#{password_field}").nil?)) ||
|
|
91
|
+
controller && (controller.cookies[:"crowd.token_key"] || controller.session[:"crowd.token_key"] || controller.params["crowd.token_key"]))
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def authenticating_with_password?
|
|
95
|
+
!authenticating_with_crowd? && login_field && (!send(login_field).nil? || !send("protected_#{password_field}").nil?)
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def sso?
|
|
99
|
+
self.class.crowd_sso
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
# def credentials
|
|
103
|
+
# if authenticating_with_crowd?
|
|
104
|
+
# details = {}
|
|
105
|
+
# details[login_field.to_sym] = send(login_field)
|
|
106
|
+
# details[password_field.to_sym] = "<protected>"
|
|
107
|
+
# details[crowd_user_token_field.to_sym] = send(crowd_user_token_field)
|
|
108
|
+
# details
|
|
109
|
+
# else
|
|
110
|
+
# super
|
|
111
|
+
# end
|
|
112
|
+
# end
|
|
113
|
+
|
|
114
|
+
def credentials=(value)
|
|
115
|
+
super
|
|
116
|
+
values = value.is_a?(Array) ? value : [value]
|
|
117
|
+
if values.first.is_a?(Hash)
|
|
118
|
+
values.first.with_indifferent_access.slice(login_field, password_field).each do |field, value|
|
|
119
|
+
next if value.blank?
|
|
120
|
+
send("#{field}=", value)
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
private
|
|
126
|
+
|
|
127
|
+
# Main session validation using Crowd user token.
|
|
128
|
+
# Uses simple_crowd to verify the user token on the configured crowd server
|
|
129
|
+
# If no *local* user is found and auto_register is enabled (default) then automatically create *local* user for them
|
|
130
|
+
# TODO: Cleanup and figure out reason for duplicate calls
|
|
131
|
+
def validate_by_crowd
|
|
132
|
+
begin
|
|
133
|
+
load_crowd_app_token
|
|
134
|
+
login = send(login_field) || (unauthorized_record && unauthorized_record.login)
|
|
135
|
+
password = send("protected_#{password_field}")
|
|
136
|
+
params_user_token = controller && controller.params["crowd.token_key"]
|
|
137
|
+
session_user_token = controller && controller.session[:"crowd.token_key"]
|
|
138
|
+
cookie_user_token = sso? && controller && controller.cookies[:"crowd.token_key"]
|
|
139
|
+
user_token = crowd_user_token
|
|
140
|
+
crowd_user = nil
|
|
141
|
+
|
|
142
|
+
# Lets see if the user passed in an email or a login using the db
|
|
143
|
+
if !login.blank? && self.unauthorized_record.nil?
|
|
144
|
+
self.unauthorized_record = klass.respond_to?(:login_or_email_equals) ?
|
|
145
|
+
klass.send(:login_or_email_equals, login).first :
|
|
146
|
+
klass.send("find_by_#{login_field}", login)
|
|
147
|
+
# If passed in login equals the user email then get the REAL login used by crowd instead
|
|
148
|
+
login = unauthorized_record.login if !unauthorized_record.nil? && login = unauthorized_record.email
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
if user_token && crowd_client.is_valid_user_token?(user_token)
|
|
152
|
+
elsif login && password
|
|
153
|
+
# Authenticate if we don't have token
|
|
154
|
+
user_token = crowd_client.authenticate_user login, password rescue nil
|
|
155
|
+
|
|
156
|
+
# Try one last time to login with crowd email field instead of login
|
|
157
|
+
if user_token.nil? && self.unauthorized_record.nil? && login =~ Authlogic::Regex.email
|
|
158
|
+
crowd_user ||= crowd_client.find_user_by_email(login)
|
|
159
|
+
if crowd_user
|
|
160
|
+
login = crowd_user.username
|
|
161
|
+
user_token = crowd_client.authenticate_user login, password rescue nil
|
|
162
|
+
end
|
|
163
|
+
end
|
|
164
|
+
else
|
|
165
|
+
user_token = nil
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
raise "No user token" if user_token.blank?
|
|
169
|
+
|
|
170
|
+
login = crowd_client.find_username_by_token user_token unless login &&
|
|
171
|
+
(!cookie_user_token || session_user_token == cookie_user_token) &&
|
|
172
|
+
(!params_user_token || session_user_token == params_user_token)
|
|
173
|
+
send("#{login_field}=", login)
|
|
174
|
+
|
|
175
|
+
self.class.crowd_user_token = user_token
|
|
176
|
+
|
|
177
|
+
if !self.unauthorized_record.nil? && self.unauthorized_record.login == login
|
|
178
|
+
self.attempted_record = self.unauthorized_record
|
|
179
|
+
else
|
|
180
|
+
self.attempted_record = self.unauthorized_record = klass.send(:"find_by_#{login_field}", login)
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
if !attempted_record
|
|
184
|
+
# If auto_register enabled then create new user with crowd info
|
|
185
|
+
if auto_register?
|
|
186
|
+
crowd_user ||= crowd_client.find_user_by_token user_token
|
|
187
|
+
self.attempted_record = klass.new :login => crowd_user.username, :email => crowd_user.email
|
|
188
|
+
self.new_registration = true
|
|
189
|
+
self.attempted_record.crowd_record = crowd_user
|
|
190
|
+
self.crowd_record = crowd_user
|
|
191
|
+
sync
|
|
192
|
+
self.attempted_record.save_without_session_maintenance
|
|
193
|
+
else
|
|
194
|
+
errors.add_to_base("We did not find any accounts with that login. Enter your details and create an account.")
|
|
195
|
+
return false
|
|
196
|
+
end
|
|
197
|
+
end
|
|
198
|
+
rescue Exception => e
|
|
199
|
+
errors.add_to_base("Authentication failed. Please try again")
|
|
200
|
+
# Don't know why it doesn't work the first time,
|
|
201
|
+
# but if we nil the session key here then the session doesn't get deleted
|
|
202
|
+
# Leaving the token triggers the validation a second time and successfully destroys the session
|
|
203
|
+
# REMOVED AS HACK
|
|
204
|
+
# Hack to fix user_credentials not being deleted on session destroy
|
|
205
|
+
|
|
206
|
+
if controller
|
|
207
|
+
controller.session[:"crowd.token_key"] = nil
|
|
208
|
+
unless (send(login_field) || (unauthorized_record && unauthorized_record.login) && send("protected_#{password_field}"))
|
|
209
|
+
# Hack to try and check session without recreating it. (we only want to destroy it if it exists already)
|
|
210
|
+
# This is to avoid a infinite recursive session creation bug we had a while back
|
|
211
|
+
curr_klass = klass
|
|
212
|
+
curr_session = controller.instance_eval { @current_user_session }
|
|
213
|
+
curr_session.destroy if curr_session
|
|
214
|
+
controller.session.clear
|
|
215
|
+
end
|
|
216
|
+
# Delete by klass name instead of generic user
|
|
217
|
+
controller.cookies.delete :"#{klass.name.underscore}_credentials"
|
|
218
|
+
controller.cookies.delete :"crowd.token_key", :domain => crowd_cookie_info[:domain] if sso?
|
|
219
|
+
end
|
|
220
|
+
false
|
|
221
|
+
end
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
def sync_with_crowd
|
|
225
|
+
# If it's a new registration then the crowd data was just pulled, so skip syncing on login
|
|
226
|
+
unless new_registration? || !self.attempted_record
|
|
227
|
+
login = send(login_field) || (!attempted_record.nil? && attempted_record.login)
|
|
228
|
+
user_token = controller && (controller.params["crowd.token_key"] || controller.cookies[:"crowd.token_key"] || controller.session[:"crowd.token_key"])
|
|
229
|
+
crowd_user = if login
|
|
230
|
+
crowd_client.find_user_by_name login
|
|
231
|
+
elsif user_token
|
|
232
|
+
crowd_client.find_user_by_token user_token
|
|
233
|
+
end
|
|
234
|
+
if crowd_user && before_sync
|
|
235
|
+
self.crowd_record = crowd_user
|
|
236
|
+
# Callbacks to sync data
|
|
237
|
+
sync
|
|
238
|
+
self.attempted_record.save
|
|
239
|
+
after_sync
|
|
240
|
+
end
|
|
241
|
+
end
|
|
242
|
+
end
|
|
243
|
+
|
|
244
|
+
# Single Sign-out
|
|
245
|
+
def logout_of_crowd
|
|
246
|
+
# Send an invalidate call for single signout
|
|
247
|
+
# Apparently there is no way of knowing if this was successful or not.
|
|
248
|
+
crowd_client.invalidate_user_token crowd_user_token unless crowd_user_token.nil?
|
|
249
|
+
# Remove cookie and session
|
|
250
|
+
if controller
|
|
251
|
+
controller.session[:"crowd.token_key"] = nil
|
|
252
|
+
controller.cookies.delete :"crowd.token_key", :domain => crowd_cookie_info[:domain] if sso?
|
|
253
|
+
controller.cookies.delete :"#{klass.name.underscore}_credentials"
|
|
254
|
+
end
|
|
255
|
+
true
|
|
256
|
+
end
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
def crowd_user_token
|
|
260
|
+
self.class.crowd_user_token
|
|
261
|
+
end
|
|
262
|
+
def crowd_client
|
|
263
|
+
@crowd_client ||= SimpleCrowd::Client.new(crowd_config)
|
|
264
|
+
end
|
|
265
|
+
def load_crowd_app_token
|
|
266
|
+
cached_token = Rails.cache.read('crowd_app_token')
|
|
267
|
+
crowd_client.app_token = cached_token unless cached_token.nil?
|
|
268
|
+
Rails.cache.write('crowd_app_token', crowd_client.app_token) unless cached_token == crowd_client.app_token
|
|
269
|
+
end
|
|
270
|
+
def crowd_cookie_info
|
|
271
|
+
unless @crowd_cookie_info
|
|
272
|
+
cached_info = Rails.cache.read('crowd_cookie_info')
|
|
273
|
+
@crowd_cookie_info ||= cached_info || crowd_client.get_cookie_info
|
|
274
|
+
Rails.cache.write('crowd_cookie_info', @crowd_cookie_info) unless cached_info == @crowd_cookie_info
|
|
275
|
+
end
|
|
276
|
+
@crowd_cookie_info
|
|
277
|
+
end
|
|
278
|
+
def crowd_config
|
|
279
|
+
{:service_url => klass.crowd_service_url,
|
|
280
|
+
:app_name => klass.crowd_app_name,
|
|
281
|
+
:app_password => klass.crowd_app_password}
|
|
282
|
+
end
|
|
283
|
+
end
|
|
284
|
+
end
|
|
285
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
module AuthlogicCrowd
|
|
2
|
+
module SessionCallbacks
|
|
3
|
+
METHODS = [
|
|
4
|
+
"before_sync", "sync", "after_sync"
|
|
5
|
+
]
|
|
6
|
+
def self.included(base)
|
|
7
|
+
base.send :include, ActiveSupport::Callbacks
|
|
8
|
+
base.define_callbacks *METHODS
|
|
9
|
+
end
|
|
10
|
+
private
|
|
11
|
+
METHODS.each do |method|
|
|
12
|
+
class_eval <<-"end_eval", __FILE__, __LINE__
|
|
13
|
+
def #{method}
|
|
14
|
+
run_callbacks(:#{method}) { |result, object| result == false }
|
|
15
|
+
end
|
|
16
|
+
end_eval
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,9 @@
|
|
|
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)
|
data/test/helper.rb
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
require 'rubygems'
|
|
2
|
+
require 'test/unit'
|
|
3
|
+
require 'shoulda'
|
|
4
|
+
require 'matchy'
|
|
5
|
+
require 'rr'
|
|
6
|
+
|
|
7
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
|
8
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
|
9
|
+
require 'authlogic_crowd'
|
|
10
|
+
|
|
11
|
+
class Test::Unit::TestCase
|
|
12
|
+
include RR::Adapters::TestUnit
|
|
13
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: authlogic_crowd
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
hash: 17
|
|
5
|
+
prerelease:
|
|
6
|
+
segments:
|
|
7
|
+
- 0
|
|
8
|
+
- 2
|
|
9
|
+
- 3
|
|
10
|
+
version: 0.2.3
|
|
11
|
+
platform: ruby
|
|
12
|
+
authors:
|
|
13
|
+
- Paul Strong
|
|
14
|
+
autorequire:
|
|
15
|
+
bindir: bin
|
|
16
|
+
cert_chain: []
|
|
17
|
+
|
|
18
|
+
date: 2011-07-11 00:00:00 -05:00
|
|
19
|
+
default_executable:
|
|
20
|
+
dependencies:
|
|
21
|
+
- !ruby/object:Gem::Dependency
|
|
22
|
+
name: thoughtbot-shoulda
|
|
23
|
+
prerelease: false
|
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
|
25
|
+
none: false
|
|
26
|
+
requirements:
|
|
27
|
+
- - ">="
|
|
28
|
+
- !ruby/object:Gem::Version
|
|
29
|
+
hash: 3
|
|
30
|
+
segments:
|
|
31
|
+
- 0
|
|
32
|
+
version: "0"
|
|
33
|
+
type: :development
|
|
34
|
+
version_requirements: *id001
|
|
35
|
+
- !ruby/object:Gem::Dependency
|
|
36
|
+
name: fcoury-matchy
|
|
37
|
+
prerelease: false
|
|
38
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
|
39
|
+
none: false
|
|
40
|
+
requirements:
|
|
41
|
+
- - ">="
|
|
42
|
+
- !ruby/object:Gem::Version
|
|
43
|
+
hash: 3
|
|
44
|
+
segments:
|
|
45
|
+
- 0
|
|
46
|
+
version: "0"
|
|
47
|
+
type: :development
|
|
48
|
+
version_requirements: *id002
|
|
49
|
+
- !ruby/object:Gem::Dependency
|
|
50
|
+
name: rr
|
|
51
|
+
prerelease: false
|
|
52
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
|
53
|
+
none: false
|
|
54
|
+
requirements:
|
|
55
|
+
- - ">="
|
|
56
|
+
- !ruby/object:Gem::Version
|
|
57
|
+
hash: 3
|
|
58
|
+
segments:
|
|
59
|
+
- 0
|
|
60
|
+
version: "0"
|
|
61
|
+
type: :development
|
|
62
|
+
version_requirements: *id003
|
|
63
|
+
- !ruby/object:Gem::Dependency
|
|
64
|
+
name: authlogic
|
|
65
|
+
prerelease: false
|
|
66
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
|
67
|
+
none: false
|
|
68
|
+
requirements:
|
|
69
|
+
- - ">="
|
|
70
|
+
- !ruby/object:Gem::Version
|
|
71
|
+
hash: 13
|
|
72
|
+
segments:
|
|
73
|
+
- 2
|
|
74
|
+
- 1
|
|
75
|
+
- 3
|
|
76
|
+
version: 2.1.3
|
|
77
|
+
- - <
|
|
78
|
+
- !ruby/object:Gem::Version
|
|
79
|
+
hash: 7
|
|
80
|
+
segments:
|
|
81
|
+
- 3
|
|
82
|
+
- 0
|
|
83
|
+
- 0
|
|
84
|
+
version: 3.0.0
|
|
85
|
+
type: :runtime
|
|
86
|
+
version_requirements: *id004
|
|
87
|
+
- !ruby/object:Gem::Dependency
|
|
88
|
+
name: simple_crowd
|
|
89
|
+
prerelease: false
|
|
90
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
|
91
|
+
none: false
|
|
92
|
+
requirements:
|
|
93
|
+
- - ">="
|
|
94
|
+
- !ruby/object:Gem::Version
|
|
95
|
+
hash: 23
|
|
96
|
+
segments:
|
|
97
|
+
- 1
|
|
98
|
+
- 0
|
|
99
|
+
- 0
|
|
100
|
+
version: 1.0.0
|
|
101
|
+
type: :runtime
|
|
102
|
+
version_requirements: *id005
|
|
103
|
+
description: Authlogic Crowd
|
|
104
|
+
email: paul@thestrongfamily.org
|
|
105
|
+
executables: []
|
|
106
|
+
|
|
107
|
+
extensions: []
|
|
108
|
+
|
|
109
|
+
extra_rdoc_files:
|
|
110
|
+
- README.rdoc
|
|
111
|
+
files:
|
|
112
|
+
- .document
|
|
113
|
+
- .gitignore
|
|
114
|
+
- Gemfile
|
|
115
|
+
- README.rdoc
|
|
116
|
+
- Rakefile
|
|
117
|
+
- authlogic_crowd.gemspec
|
|
118
|
+
- lib/authlogic_crowd.rb
|
|
119
|
+
- lib/authlogic_crowd/acts_as_authentic.rb
|
|
120
|
+
- lib/authlogic_crowd/acts_as_authentic_callbacks.rb
|
|
121
|
+
- lib/authlogic_crowd/session.rb
|
|
122
|
+
- lib/authlogic_crowd/session_callbacks.rb
|
|
123
|
+
- lib/authlogic_crowd/version.rb
|
|
124
|
+
- test/helper.rb
|
|
125
|
+
- test/test_authlogic_crowd.rb
|
|
126
|
+
has_rdoc: true
|
|
127
|
+
homepage: http://github.com/lapluviosilla/authlogic_crowd
|
|
128
|
+
licenses: []
|
|
129
|
+
|
|
130
|
+
post_install_message:
|
|
131
|
+
rdoc_options: []
|
|
132
|
+
|
|
133
|
+
require_paths:
|
|
134
|
+
- lib
|
|
135
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
136
|
+
none: false
|
|
137
|
+
requirements:
|
|
138
|
+
- - ">="
|
|
139
|
+
- !ruby/object:Gem::Version
|
|
140
|
+
hash: 3
|
|
141
|
+
segments:
|
|
142
|
+
- 0
|
|
143
|
+
version: "0"
|
|
144
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
145
|
+
none: false
|
|
146
|
+
requirements:
|
|
147
|
+
- - ">="
|
|
148
|
+
- !ruby/object:Gem::Version
|
|
149
|
+
hash: 3
|
|
150
|
+
segments:
|
|
151
|
+
- 0
|
|
152
|
+
version: "0"
|
|
153
|
+
requirements: []
|
|
154
|
+
|
|
155
|
+
rubyforge_project:
|
|
156
|
+
rubygems_version: 1.6.2
|
|
157
|
+
signing_key:
|
|
158
|
+
specification_version: 3
|
|
159
|
+
summary: Atlassian Crowd support for Authlogic
|
|
160
|
+
test_files:
|
|
161
|
+
- test/helper.rb
|
|
162
|
+
- test/test_authlogic_crowd.rb
|