ucb_rails_user 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (64) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +166 -0
  4. data/Rakefile +36 -0
  5. data/app/assets/config/ucb_rails_user_manifest.js +0 -0
  6. data/app/assets/javascripts/ucb_rails_user/datatables.js +15441 -0
  7. data/app/assets/javascripts/ucb_rails_user/scripts.js +15 -0
  8. data/app/assets/javascripts/ucb_rails_user/ucb_rails_user.js +39 -0
  9. data/app/assets/stylesheets/ucb_rails_user/components/_add_users_search_results_table.sass +2 -0
  10. data/app/assets/stylesheets/ucb_rails_user/components/_loader.sass +46 -0
  11. data/app/assets/stylesheets/ucb_rails_user/components/_users_table.sass +10 -0
  12. data/app/assets/stylesheets/ucb_rails_user/datatables.css +201 -0
  13. data/app/assets/stylesheets/ucb_rails_user/main.sass +2 -0
  14. data/app/assets/stylesheets/ucb_rails_user/styles.css +19 -0
  15. data/app/controllers/ucb_rails_user/concerns/controller_methods.rb +92 -0
  16. data/app/controllers/ucb_rails_user/concerns/home_controller.rb +17 -0
  17. data/app/controllers/ucb_rails_user/concerns/sessions_controller.rb +68 -0
  18. data/app/controllers/ucb_rails_user/concerns/users_controller.rb +132 -0
  19. data/app/controllers/ucb_rails_user/home_controller.rb +10 -0
  20. data/app/controllers/ucb_rails_user/sessions_controller.rb +9 -0
  21. data/app/controllers/ucb_rails_user/users_controller.rb +8 -0
  22. data/app/helpers/ucb_rails_user/users_helper.rb +18 -0
  23. data/app/helpers/ucb_rails_user_helper.rb +17 -0
  24. data/app/models/concerns/user_concerns.rb +53 -0
  25. data/app/models/ucb_rails_user/configuration/cas.rb +53 -0
  26. data/app/models/ucb_rails_user/configuration/configuration.rb +72 -0
  27. data/app/models/ucb_rails_user/configuration/email.rb +73 -0
  28. data/app/models/ucb_rails_user/configuration/exception_notification.rb +21 -0
  29. data/app/models/ucb_rails_user/configuration/ldap.rb +50 -0
  30. data/app/models/ucb_rails_user/ldap_person/entry.rb +62 -0
  31. data/app/models/ucb_rails_user/ldap_person/finder.rb +87 -0
  32. data/app/models/ucb_rails_user/ldap_person/test_finder.rb +57 -0
  33. data/app/models/ucb_rails_user/user_ldap_service.rb +65 -0
  34. data/app/models/ucb_rails_user/user_session_manager/active_in_user_table.rb +29 -0
  35. data/app/models/ucb_rails_user/user_session_manager/admin_in_user_table.rb +13 -0
  36. data/app/models/ucb_rails_user/user_session_manager/base.rb +54 -0
  37. data/app/models/ucb_rails_user/user_session_manager/in_people_ou.rb +27 -0
  38. data/app/models/ucb_rails_user/user_session_manager/in_people_ou_add_to_users_table.rb +21 -0
  39. data/app/models/ucb_rails_user/user_session_manager/ldap_person_user_wrapper.rb +29 -0
  40. data/app/models/user.rb +8 -0
  41. data/app/views/ucb_rails_user/home/logged_in.html.haml +5 -0
  42. data/app/views/ucb_rails_user/home/not_logged_in.html.haml +5 -0
  43. data/app/views/ucb_rails_user/lps/_form.html.haml +19 -0
  44. data/app/views/ucb_rails_user/lps/_modal.html.haml +9 -0
  45. data/app/views/ucb_rails_user/lps/_results.html.haml +34 -0
  46. data/app/views/ucb_rails_user/lps/search.js.haml +3 -0
  47. data/app/views/ucb_rails_user/users/_form.html.haml +14 -0
  48. data/app/views/ucb_rails_user/users/_search_results.html.haml +24 -0
  49. data/app/views/ucb_rails_user/users/_user.html.haml +12 -0
  50. data/app/views/ucb_rails_user/users/edit.html.haml +3 -0
  51. data/app/views/ucb_rails_user/users/index.html.haml +23 -0
  52. data/app/views/ucb_rails_user/users/new.html.haml +16 -0
  53. data/app/views/ucb_rails_user/users/search.js.haml +4 -0
  54. data/config/initializers/simple_form.rb +171 -0
  55. data/config/initializers/simple_form_bootstrap.rb +154 -0
  56. data/config/locales/simple_form.en.yml +31 -0
  57. data/config/routes.rb +20 -0
  58. data/db/migrate/20170324221936_create_users.rb +29 -0
  59. data/lib/tasks/ucb_rails_user_tasks.rake +4 -0
  60. data/lib/templates/erb/scaffold/_form.html.erb +13 -0
  61. data/lib/ucb_rails_user.rb +21 -0
  62. data/lib/ucb_rails_user/engine.rb +28 -0
  63. data/lib/ucb_rails_user/version.rb +3 -0
  64. metadata +277 -0
@@ -0,0 +1,73 @@
1
+ module UcbRailsUser
2
+ module Configuration
3
+ class Email
4
+ ArgumentError = Class.new(StandardError)
5
+
6
+ attr_accessor :hash
7
+
8
+ def self.configure(config)
9
+ new(config)
10
+ end
11
+
12
+ def initialize(configuration_hash)
13
+ return if configuration_hash.nil?
14
+ raise(ArgumentError, "expected a Hash, got: #{configuration_hash.inspect}") unless configuration_hash.is_a?(Hash)
15
+
16
+ self.hash = configuration_hash
17
+ process_configuration
18
+ end
19
+
20
+ private
21
+
22
+ def process_configuration
23
+ process_default
24
+ process_delivery_method
25
+ process_default_url_options
26
+ process_raise_delivery_errors
27
+ process_sendmail_settings
28
+ process_smtp_settings
29
+ process_subject_prefix
30
+ end
31
+
32
+ # This merges values with existing values
33
+ def process_default
34
+ if hash.has_key?('default')
35
+ ActionMailer::Base.default hash['default']
36
+ end
37
+ end
38
+
39
+ def process_delivery_method
40
+ ActionMailer::Base.delivery_method = hash.fetch('delivery_method', :smtp).to_sym
41
+ end
42
+
43
+ def process_default_url_options
44
+ if hash.has_key?('default_url_options')
45
+ ActionMailer::Base.default_url_options = hash.fetch('default_url_options').symbolize_keys
46
+ end
47
+ end
48
+
49
+ def process_raise_delivery_errors
50
+ ActionMailer::Base.raise_delivery_errors = hash.fetch('raise_delivery_errors', true)
51
+ end
52
+
53
+ def process_sendmail_settings
54
+ if hash.has_key?('sendmail_settings')
55
+ ActionMailer::Base.sendmail_settings = hash.fetch('sendmail_settings').symbolize_keys
56
+ end
57
+ end
58
+
59
+ def process_smtp_settings
60
+ if hash.has_key?('smtp_settings')
61
+ ActionMailer::Base.smtp_settings = hash.fetch('smtp_settings').symbolize_keys
62
+ end
63
+ end
64
+
65
+ def process_subject_prefix
66
+ prefix = hash.fetch('subject_prefix', '')
67
+ prefix = prefix.gsub("{env}", Rails.env)
68
+ UcbRailsUser.config.email_subject_prefix = prefix
69
+ end
70
+ end
71
+
72
+ end
73
+ end
@@ -0,0 +1,21 @@
1
+ module UcbRailsUser
2
+ module Configuration
3
+
4
+ class ExceptionNotification
5
+
6
+ class << self
7
+
8
+ def configure(config)
9
+ return if config.blank?
10
+
11
+ config = config.symbolize_keys
12
+ config[:email].symbolize_keys!
13
+ config[:email][:email_prefix] = config[:email][:email_prefix].gsub("{env}", RailsEnvironment.short)
14
+
15
+ Rails.application.config.middleware.use ::ExceptionNotification::Rack, config
16
+ end
17
+ end
18
+ end
19
+
20
+ end
21
+ end
@@ -0,0 +1,50 @@
1
+ module UcbRailsUser
2
+ module Configuration
3
+
4
+ class Ldap
5
+ attr_accessor :config
6
+
7
+ def initialize(config)
8
+ self.config = config.presence || {}
9
+ end
10
+
11
+ def configure
12
+ configure_host
13
+ initialize_ldap
14
+ test_entries
15
+ end
16
+
17
+ private
18
+
19
+ def configure_host
20
+ UCB::LDAP.host = config.fetch("host", default_host)
21
+ end
22
+
23
+ def initialize_ldap
24
+ username = config.fetch("username", "")
25
+ password = config.fetch("password", "")
26
+ host = config.fetch("host", "")
27
+ UCB::LDAP.initialize username, password, host
28
+ end
29
+
30
+ def test_entries
31
+ UCB::LDAP::Person.include_test_entries = config.fetch("include_test_entries", default_include_test_entries)
32
+ end
33
+
34
+ def default_host
35
+ "nds.berkeley.edu"
36
+ end
37
+
38
+ def default_include_test_entries
39
+ !Rails.env.production?
40
+ end
41
+
42
+ class << self
43
+ def configure(config)
44
+ new(config).configure
45
+ end
46
+ end
47
+ end
48
+
49
+ end
50
+ end
@@ -0,0 +1,62 @@
1
+ module UcbRailsUser::LdapPerson
2
+ class Entry
3
+
4
+ # include ActiveAttr::Model <--- doesn't work with 4.0 (mass assign. security)
5
+ include ::ActiveAttr::Attributes
6
+ include ::ActiveAttr::BasicModel
7
+ include ::ActiveAttr::BlockInitialization
8
+ include ::ActiveAttr::MassAssignment
9
+
10
+ attribute :uid
11
+ attribute :calnet_id
12
+ attribute :employee_id
13
+ attribute :student_id
14
+ attribute :first_name
15
+ attribute :last_name
16
+ attribute :email
17
+ attribute :phone
18
+ attribute :departments
19
+ attribute :affiliations
20
+ attribute :affiliate_id
21
+ attribute :inactive
22
+
23
+ def full_name
24
+ "#{first_name()} #{last_name()}"
25
+ end
26
+
27
+ def last_first
28
+ "#{last_name}, #{first_name}"
29
+ end
30
+
31
+ def last_first_downcase
32
+ last_first.downcase
33
+ end
34
+
35
+ # Currently only used in rspec
36
+ def ==(other)
37
+ uid == other.uid
38
+ end
39
+
40
+ class << self
41
+
42
+ def new_from_ldap_entry(ldap_entry)
43
+ new(
44
+ :uid => ldap_entry.uid,
45
+ :calnet_id => ldap_entry.berkeleyedukerberosprincipalstring.first,
46
+ :employee_id => ldap_entry.employeenumber,
47
+ :student_id => ldap_entry.attributes["student_id"],
48
+ :first_name => ldap_entry.givenname.first,
49
+ :last_name => ldap_entry.sn.first,
50
+ :email => ldap_entry.mail.first,
51
+ :phone => ldap_entry.phone,
52
+ :departments => ldap_entry.berkeleyeduunithrdeptname,
53
+ :affiliations => ldap_entry.berkeleyeduaffiliations,
54
+ :affiliate_id => ldap_entry.berkeleyeduaffid.first,
55
+ :inactive => ldap_entry.expired? || false
56
+ )
57
+ end
58
+
59
+ end
60
+
61
+ end
62
+ end
@@ -0,0 +1,87 @@
1
+ module UcbRailsUser::LdapPerson
2
+ class Finder
3
+ BlankSearchTermsError = Class.new(StandardError)
4
+ PersonNotFound = Class.new(StandardError)
5
+
6
+ def benchmark(message = "Benchmarking")
7
+ result = nil
8
+ ms = Benchmark.ms { result = yield }
9
+ Rails.logger.debug "#{message} #{ms}"
10
+ result
11
+ end
12
+
13
+ def find_by_uid(uid)
14
+ benchmark("find_by_uid(#{uid})") do
15
+ find_by_attributes(:uid => uid.to_s).first ||
16
+ find_expired_by_attributes(:uid => uid.to_s).first
17
+ end
18
+ end
19
+
20
+ def find_by_uid!(uid)
21
+ find_by_uid(uid) or raise(PersonNotFound, "uid=#{uid.inspect}")
22
+ end
23
+
24
+ def find_by_first_last(first_name, last_name, options={})
25
+ raise BlankSearchTermsError unless first_name.present? || last_name.present?
26
+
27
+ find_by_attributes({:givenname => first_name, :sn => last_name}, options).tap do |entries|
28
+ if options[:sort]
29
+ sort_symbol = options[:sort]
30
+ entries.sort_by!(&options[:sort])
31
+ end
32
+ end
33
+ end
34
+
35
+ def find_by_affiliate_id(affiliate_id)
36
+ find_by_attributes("berkeleyEduAffID" => affiliate_id)
37
+ end
38
+
39
+ def find_by_attributes(attributes, options={})
40
+ attributes.each { |k, v| attributes.delete(k) if v.blank? }
41
+
42
+ search_opts = { :filter => build_filter(attributes, options) }
43
+ search_opts[:return_result] = options[:return_result] if options.has_key?(:return_result)
44
+ search_opts[:size] = options[:size] if options.has_key?(:size)
45
+
46
+ UCB::LDAP::Person.
47
+ search(search_opts).
48
+ map { |ldap_entry| Entry.new_from_ldap_entry(ldap_entry) }
49
+ end
50
+
51
+ def find_expired_by_attributes(attributes)
52
+ attributes.each { |k, v| attributes.delete(k) if v.blank? }
53
+ UCB::LDAP::ExpiredPerson.
54
+ search(:filter => build_filter(attributes)).
55
+ map { |ldap_entry| Entry.new_from_ldap_entry(ldap_entry) }
56
+ end
57
+
58
+ def build_filter(attrs, options={})
59
+ operator = options[:operator] || :&
60
+ filter_parts = attrs.map { |k, values|
61
+ Array(values).map{|v| build_filter_part(k, v) }
62
+ }.flatten
63
+ filter = filter_parts.inject { |accum, filter| accum.send(operator, filter) }
64
+ filter
65
+ end
66
+
67
+ def build_filter_part(key, value)
68
+ value = key.to_s == 'uid' ? value : "#{value}*"
69
+ Net::LDAP::Filter.eq(key.to_s, value)
70
+ end
71
+
72
+ class << self
73
+ def klass
74
+ if Rails.env.test? || UcbRailsUser[:omniauth_provider] == :developer
75
+ UcbRailsUser::LdapPerson::TestFinder
76
+ else
77
+ UcbRailsUser::LdapPerson::Finder
78
+ end
79
+ end
80
+
81
+ def method_missing(method, *args)
82
+ klass.new.send(method, *args)
83
+ end
84
+ end
85
+
86
+ end
87
+ end
@@ -0,0 +1,57 @@
1
+ module UcbRailsUser::LdapPerson
2
+ class TestFinder
3
+ PersonNotFound = Class.new(StandardError)
4
+
5
+ def find_by_uid(uid)
6
+ uid.presence and find_by_attributes(:uid => uid.to_s).first
7
+ end
8
+
9
+ def find_by_uid!(uid)
10
+ find_by_uid(uid) || raise(PersonNotFound, "uid=#{uid.inspect}")
11
+ end
12
+
13
+ def find_by_first_last(first_name, last_name, options={})
14
+ find_by_attributes(:first_name => first_name, :last_name => last_name)
15
+ end
16
+
17
+ def find_by_affiliate_id(affiliate_id)
18
+ find_by_attributes("affiliate_id" => affiliate_id)
19
+ end
20
+
21
+ def find_by_attributes(attributes)
22
+ self.class.entries.select { |entry| entry_matches_attributes(entry, attributes) }
23
+ end
24
+
25
+ def entry_matches_attributes(entry, attributes)
26
+ attributes.keys.all? do |key|
27
+ value = attributes[key].to_s.downcase
28
+ value.blank? || (entry.respond_to?(key) && entry.send(key).to_s.downcase.include?(value))
29
+ end
30
+ end
31
+
32
+ def self.entries
33
+ [
34
+ new_entry("1", 'art', "Art", "Andrews", "art@example.com", "999-999-0001", "Dept 1", "011"),
35
+ new_entry("2", 'beth', "Beth", "Brown", "beth@example.com", "999-999-0002", "Dept 2", "012"),
36
+ new_entry("61065", 'runner', "Steven", "Hansen", "runner@berkeley.edu", "999-999-9998", "EAS", "0161065"),
37
+ new_entry("191501", 'stevedowney', "Steve", "Downey", "sldowney@berkeley.edu", "999-999-9999", "EAS", "01191501"),
38
+ ]
39
+ end
40
+
41
+ def self.new_entry(uid, calnet_id, fn, ln, email, phone, depts, employee_id = nil, affiliate_id = nil)
42
+ ::UcbRailsUser::LdapPerson::Entry.new(
43
+ :uid => uid,
44
+ :calnet_id => calnet_id,
45
+ :first_name => fn,
46
+ :last_name => ln,
47
+ :email => email,
48
+ :phone => phone,
49
+ :departments => depts,
50
+ :employee_id => employee_id,
51
+ :affiliate_id => affiliate_id,
52
+ :inactive => false
53
+ )
54
+ end
55
+
56
+ end
57
+ end
@@ -0,0 +1,65 @@
1
+ class UcbRailsUser::UserLdapService
2
+
3
+ class << self
4
+
5
+ def create_user_from_uid(uid)
6
+ UcbRailsUser.logger.debug "create_user_from_uid #{uid}"
7
+
8
+ ldap_entry = UcbRailsUser::LdapPerson::Finder.find_by_uid!(uid)
9
+ create_user_from_ldap_entry(ldap_entry)
10
+ end
11
+
12
+ def create_user_from_ldap_entry(ldap_entry)
13
+ UcbRailsUser.logger.debug "create_user_from_ldap_entry #{ldap_entry.uid}"
14
+
15
+ User.create! do |u|
16
+ u.ldap_uid = ldap_entry.uid
17
+ u.employee_id = ldap_entry.employee_id
18
+ u.affiliate_id = ldap_entry.affiliate_id
19
+ u.student_id = ldap_entry.student_id
20
+ u.first_name = ldap_entry.first_name
21
+ u.last_name = ldap_entry.last_name
22
+ u.email = ldap_entry.email
23
+ u.inactive_flag = ldap_entry.inactive
24
+ end
25
+ end
26
+
27
+ def update_user_from_uid(uid)
28
+ UcbRailsUser.logger.debug "update_user_from_uid #{uid}"
29
+
30
+ ldap_entry = UcbRailsUser::LdapPerson::Finder.find_by_uid!(uid)
31
+ update_user_from_ldap_entry(ldap_entry)
32
+ end
33
+
34
+ def update_user_from_ldap_entry(ldap_entry)
35
+ UcbRailsUser.logger.debug "update_user_from_ldap_entry #{ldap_entry.uid}"
36
+
37
+ User.find_by_ldap_uid!(ldap_entry.uid).tap do |user|
38
+ user.employee_id = ldap_entry.employee_id if user.respond_to?(:employee_id=)
39
+ user.first_name = ldap_entry.first_name
40
+ user.last_name = ldap_entry.last_name
41
+ user.email = ldap_entry.email
42
+ user.save(validate: false)
43
+ end
44
+ end
45
+
46
+ def create_or_update_user(uid)
47
+ if user = User.find_by_ldap_uid(uid)
48
+ update_user_from_uid(uid)
49
+ else
50
+ create_user_from_uid(uid)
51
+ end
52
+ end
53
+
54
+ def create_or_update_user_from_entry(entry)
55
+ # LDAP returns some values as Net::BER::BerIdentifiedString instances, and not
56
+ # all DBs seem to handle that well (e.g. Oracle) - we might want to fix LDAP library
57
+ # to smooth this over?
58
+ if user = User.find_by_ldap_uid(entry.uid.to_s)
59
+ update_user_from_ldap_entry(entry)
60
+ else
61
+ create_user_from_ldap_entry(entry)
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,29 @@
1
+ module UcbRailsUser
2
+ module UserSessionManager
3
+ class ActiveInUserTable < Base
4
+
5
+ def login(uid)
6
+ self.uid = uid
7
+
8
+ if user_table_entry && people_ou_entry
9
+ UcbRailsUser::UserLdapService.update_user_from_ldap_entry(people_ou_entry).tap do |user|
10
+ user.touch(:last_login_at)
11
+ end
12
+ else
13
+ false
14
+ end
15
+ end
16
+
17
+ def current_user(uid)
18
+ User.find_by_ldap_uid(uid)
19
+ end
20
+
21
+ private
22
+
23
+ def user_table_entry
24
+ active_user
25
+ end
26
+
27
+ end
28
+ end
29
+ end