ucb_rails_user 4.0.7 → 4.1.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3a8118f9d0b261b1ad04181b2fa0211c30535bedb47b75b1438275b6ef7c5af0
4
- data.tar.gz: 7eee880cef304680125f21beaffeab8a6c95525beda0bfdb750920ab4c996f2e
3
+ metadata.gz: 7a1de8958c36cbeeb3541649d812e7288468672f9352ec84749810fccaf81005
4
+ data.tar.gz: e2262f788179205abf8dc7d4558a434f3826130f6d713448ef90a783e2341fe1
5
5
  SHA512:
6
- metadata.gz: 9567b7aa7b943fd70cfe138345d191a84d36a92455e1eb0b6d1d472eb1bc17d09beea6c854804a7e8facea817ed8e2616ece9e27df6dda10bf95fc51e88911b8
7
- data.tar.gz: 7e074a6ae931a175285882810cede02a0e83d0322d1c50302d2139df7e9230af1891e8015df91e59132cb27071e4e479b30bc1b0cacb1786b93452c2612e4e30
6
+ metadata.gz: 27314e556fa6987b12779ea570dacbd3f5089a7cfdef91a316020f13754ceb147cd74de4e3e468a298109cc1336beef659708507bde98605743242e9cd4f6c91
7
+ data.tar.gz: dbb93ff5a2cde7347e2b5441155edafae6f18557cbaf584ac6f89fdb34adda7b67dc36b8f43a5c571e2fb0b6de8eefd71dacb6f3a3e6cd04458a56acd1d417fe
data/README.md CHANGED
@@ -105,6 +105,20 @@ For example, if the admin screens for your app are under the `/backend` path rat
105
105
  resources :users, controller: "ucb_rails_user/users", path: "backend/users", as: :backend_users
106
106
  ```
107
107
 
108
+ ## Session Managers
109
+
110
+ Authentication during login is handled by UCB's central auth system and this gem uses the [omniauth-cas](https://github.com/dlindahl/omniauth-cas) to manage the handshake. Once that is completed, we're handed the LDAP uid of the authenticated user, and, by default, this gem will attempt to pull the user's employee data and create or update a `User` record for them in the local database.
111
+
112
+ This behavior can be customized by writing your own user session manager. There are two steps to do this:
113
+
114
+ 1. Create a subclass of [`UcbRailsUser::UserSessionManager::Base`](https://github.com/ucb-ist-eas/ucb_rails_user/blob/main/app/models/ucb_rails_user/user_session_manager/base.rb). At a minimum you need to implement a `login` method that accepts the user's LDAP uid and returns a `User` instance (or raises an error if the process fails), and a `current_user` method that returns the `User` instance for the currently-logged-in user. [Several implementations](https://github.com/ucb-ist-eas/ucb_rails_user/tree/main/app/models/ucb_rails_user/user_session_manager) are included so you can look to these to base yours off of.
115
+
116
+ 1. Open `config/initializers/ucb_rails_user.rb` in your host app and change the `user_session_manager` config setting to the class your custom implementation:
117
+
118
+ ```
119
+ config.user_session_manager = "MyApp::MyCustomUserSessionManager"
120
+ ```
121
+
108
122
  ## User Impersonation
109
123
 
110
124
  The impersonation feature allows admins to be logged in as a different user in the system. This is useful when trying to diagnose data-specific problems, as the admin can see exactly what the user sees.
@@ -32,7 +32,7 @@ var addDatatablesToUsersTable = function () {
32
32
  }],
33
33
  })
34
34
  var addNewHtml = '&nbsp;&nbsp;<a href="/admin/users/new" class="btn btn-primary">Add New</a>'
35
- $('#DataTables_Table_0_filter').append(addNewHtml)
35
+ $('.ucb-rails-users-table-wrapper #DataTables_Table_0_filter').append(addNewHtml)
36
36
  }
37
37
 
38
38
  var resetImpersonateButton = function() {
@@ -1,8 +1,8 @@
1
1
  class UcbRailsUser::Impersonation < ApplicationRecord
2
2
  include UcbRailsUser::Concerns::ImpersonationConcerns
3
3
 
4
- # Don't add anything more here - any logic for the User class should go into
5
- # UserConcerns. This will make it much easier for host apps to customize
4
+ # Don't add anything more here - any logic for the Impersonation class should go into
5
+ # ImpersonationConcerns. This will make it much easier for host apps to customize
6
6
  # behavior if they need to
7
7
  # http://guides.rubyonrails.org/engines.html#implementing-decorator-pattern-using-activesupport-concern
8
8
 
@@ -0,0 +1,39 @@
1
+ # Session manager that attempts to pull the user record from UCPath, and
2
+ # falls back to LDAP if needed
3
+
4
+ module UcbRailsUser
5
+ module UserSessionManager
6
+
7
+ class InUcPathAddToUsersTable < ActiveInUserTable
8
+ def login(uid)
9
+ self.uid = uid
10
+
11
+ # try UCPath first
12
+ user = safely_load_user_from_api do
13
+ UcbRailsUser::UserUcPathService.create_or_update_user_from_ldap_uid(self.uid)
14
+ end
15
+
16
+ # if that doesn't work, try LDAP
17
+ user ||= safely_load_user_from_api do
18
+ UcbRailsUser::UserLdapService.create_or_update_user_from_entry(people_ou_entry)
19
+ end
20
+
21
+ user&.tap do |u|
22
+ u&.touch(:last_login_at)
23
+ end
24
+ end
25
+
26
+ private
27
+
28
+ def safely_load_user_from_api(&block)
29
+ begin
30
+ user = block.call
31
+ rescue StandardError
32
+ user = nil
33
+ end
34
+ user
35
+ end
36
+ end
37
+
38
+ end
39
+ end
@@ -0,0 +1,121 @@
1
+ require "faraday"
2
+
3
+ class UcbRailsUser::UserUcPathService
4
+
5
+ class << self
6
+
7
+ def create_or_update_user_from_employee_id(employee_id)
8
+ ucpath_entry = ucpath_client.fetch_employee_data_with_employee_id(employee_id)
9
+ return nil unless ucpath_entry.present?
10
+ user = User.find_or_initialize_by(employee_id: employee_id)
11
+ update_user_record_from_ucpath_entry!(user, ucpath_entry)
12
+ end
13
+
14
+ def create_or_update_user_from_ldap_uid(ldap_uid)
15
+ ucpath_entry = ucpath_client.fetch_employee_data_with_ldap_uid(ldap_uid)
16
+ return nil unless ucpath_entry.present?
17
+ user = User.find_or_initialize_by(ldap_uid: ldap_uid)
18
+ update_user_record_from_ucpath_entry!(user, ucpath_entry)
19
+ end
20
+
21
+ def ucpath_client
22
+ UcPathClient.new
23
+ end
24
+
25
+ def update_user_record_from_ucpath_entry!(user, ucpath_entry)
26
+ user.tap do |u|
27
+ name_entry = parse_name(ucpath_entry)
28
+ u.first_name = name_entry["givenName"]
29
+ u.last_name = name_entry["familyName"]
30
+ u.employee_id ||= ucpath_entry["identifiers"]&.detect do |id|
31
+ id["type"] == "hr-employee-id"
32
+ end&.fetch("id")
33
+ u.ldap_uid ||= ucpath_entry["identifiers"]&.detect do |id|
34
+ id["type"] == "campus-uid"
35
+ end&.fetch("id")
36
+ u.email = parse_email(ucpath_entry)
37
+ u.inactive_flag = false # any way to pull this from the API?
38
+ u.save!
39
+ end
40
+ end
41
+
42
+ def parse_name(entry)
43
+ return nil unless entry.present?
44
+ find_name_by_type(entry["names"], "PRF") ||
45
+ find_name_by_type(entry["names"], "PRI")
46
+ end
47
+
48
+ def find_name_by_type(names, type)
49
+ names&.detect do |n|
50
+ n.dig("type", "code") == type
51
+ end
52
+ end
53
+
54
+ def parse_email(entry)
55
+ email_entry =
56
+ entry["emails"]&.detect do |email|
57
+ email["primary"] == true
58
+ end
59
+ email_entry ||= entry["emails"]&.first # if there's no primary email, grab whatever we can
60
+ email_entry&.fetch("emailAddress")
61
+ end
62
+
63
+ end
64
+
65
+ class UcPathClient
66
+ attr_reader :app_id, :app_key, :endpoint
67
+
68
+ def initialize
69
+ base_credentials =
70
+ Rails.application.credentials.ucpath&.with_indifferent_access ||
71
+ Rails.application.credentials.hcm&.with_indifferent_access ||
72
+ Rails.application.credentials.fetch(:"ucb-hcm", {})&.with_indifferent_access
73
+ env_credentials = base_credentials&.fetch(Rails.env, {})
74
+ @app_id = env_credentials&.fetch(:app_id, nil) || base_credentials&.fetch(:app_id, nil)
75
+ @app_key = env_credentials&.fetch(:app_key, nil) || base_credentials&.fetch(:app_key, nil)
76
+ @endpoint = env_credentials&.fetch(:endpoint, nil) || base_credentials&.fetch(:endpoint, nil)
77
+ end
78
+
79
+ def fetch_employee_data_with_ldap_uid(ldap_uid)
80
+ fetch_employee_data(ldap_uid, "campus-uid")
81
+ end
82
+
83
+ def fetch_employee_data_with_employee_id(employee_id)
84
+ fetch_employee_data(employee_id, "hr-employee-id")
85
+ end
86
+
87
+ def fetch_employee_data(id, id_type)
88
+ if [app_id, app_key, endpoint].any?(&:blank?)
89
+ Rails.logger.warn missing_api_values_message
90
+ return nil
91
+ end
92
+ response =
93
+ Faraday.get("#{endpoint}/employees/#{id}") do |req|
94
+ req.params["id-type"] = id_type
95
+ req.headers["Accept"] = "application/json"
96
+ req.headers["app_id"] = app_id
97
+ req.headers["app_key"] = app_key
98
+ end
99
+ parse_response(response)&.first
100
+ end
101
+
102
+ private
103
+
104
+ def parse_response(response)
105
+ return nil if !response.success? || response.body.empty?
106
+ JSON.parse(response.body)&.fetch("response")
107
+ end
108
+
109
+ def missing_api_values_message
110
+ <<~END_MSG.strip
111
+ It looks like you're trying to use the preferred user name feature of
112
+ ucb_rails_user, but the host app has not provided all of the expected
113
+ credentials to access the UCPath API.
114
+ To resolve this, add an "hcm" section to the Rails credentials file of
115
+ the host app, and provide values for app_id, app_key, and endpoint.
116
+ END_MSG
117
+ end
118
+ end
119
+
120
+ end
121
+
@@ -2,7 +2,7 @@
2
2
  %h1
3
3
  Users
4
4
 
5
- .table-responsive
5
+ .table-responsive.ucb-rails-users-table-wrapper
6
6
  %table.table.table-striped.table-bordered.table-hover.ucb-rails-users-table
7
7
  %thead
8
8
  %tr
@@ -1,3 +1,3 @@
1
1
  module UcbRailsUser
2
- VERSION = '4.0.7'
2
+ VERSION = '4.1.1'
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ucb_rails_user
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.0.7
4
+ version: 4.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Steve Downey
@@ -11,7 +11,7 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2021-07-14 00:00:00.000000000 Z
14
+ date: 2022-09-14 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: rails
@@ -19,14 +19,34 @@ dependencies:
19
19
  requirements:
20
20
  - - ">"
21
21
  - !ruby/object:Gem::Version
22
- version: '5.0'
22
+ version: '5.2'
23
+ - - "<"
24
+ - !ruby/object:Gem::Version
25
+ version: '8.0'
23
26
  type: :runtime
24
27
  prerelease: false
25
28
  version_requirements: !ruby/object:Gem::Requirement
26
29
  requirements:
27
30
  - - ">"
28
31
  - !ruby/object:Gem::Version
29
- version: '5.0'
32
+ version: '5.2'
33
+ - - "<"
34
+ - !ruby/object:Gem::Version
35
+ version: '8.0'
36
+ - !ruby/object:Gem::Dependency
37
+ name: sprockets-rails
38
+ requirement: !ruby/object:Gem::Requirement
39
+ requirements:
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ version: '0'
43
+ type: :runtime
44
+ prerelease: false
45
+ version_requirements: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - ">="
48
+ - !ruby/object:Gem::Version
49
+ version: '0'
30
50
  - !ruby/object:Gem::Dependency
31
51
  name: haml
32
52
  requirement: !ruby/object:Gem::Requirement
@@ -87,16 +107,22 @@ dependencies:
87
107
  name: omniauth
88
108
  requirement: !ruby/object:Gem::Requirement
89
109
  requirements:
90
- - - "~>"
110
+ - - ">="
91
111
  - !ruby/object:Gem::Version
92
112
  version: '1.8'
113
+ - - "<"
114
+ - !ruby/object:Gem::Version
115
+ version: '3.0'
93
116
  type: :runtime
94
117
  prerelease: false
95
118
  version_requirements: !ruby/object:Gem::Requirement
96
119
  requirements:
97
- - - "~>"
120
+ - - ">="
98
121
  - !ruby/object:Gem::Version
99
122
  version: '1.8'
123
+ - - "<"
124
+ - !ruby/object:Gem::Version
125
+ version: '3.0'
100
126
  - !ruby/object:Gem::Dependency
101
127
  name: omniauth-cas
102
128
  requirement: !ruby/object:Gem::Requirement
@@ -126,53 +152,61 @@ dependencies:
126
152
  - !ruby/object:Gem::Version
127
153
  version: '3.0'
128
154
  - !ruby/object:Gem::Dependency
129
- name: puma
155
+ name: faraday
130
156
  requirement: !ruby/object:Gem::Requirement
131
157
  requirements:
132
158
  - - "~>"
133
159
  - !ruby/object:Gem::Version
134
- version: '4.3'
135
- type: :development
160
+ version: '1.0'
161
+ type: :runtime
136
162
  prerelease: false
137
163
  version_requirements: !ruby/object:Gem::Requirement
138
164
  requirements:
139
165
  - - "~>"
140
166
  - !ruby/object:Gem::Version
141
- version: '4.3'
167
+ version: '1.0'
142
168
  - !ruby/object:Gem::Dependency
143
- name: sqlite3
169
+ name: puma
144
170
  requirement: !ruby/object:Gem::Requirement
145
171
  requirements:
146
172
  - - "~>"
147
173
  - !ruby/object:Gem::Version
148
- version: '1.3'
149
- - - "<"
150
- - !ruby/object:Gem::Version
151
- version: '1.4'
174
+ version: '5.6'
152
175
  type: :development
153
176
  prerelease: false
154
177
  version_requirements: !ruby/object:Gem::Requirement
155
178
  requirements:
156
179
  - - "~>"
157
180
  - !ruby/object:Gem::Version
158
- version: '1.3'
159
- - - "<"
181
+ version: '5.6'
182
+ - !ruby/object:Gem::Dependency
183
+ name: sqlite3
184
+ requirement: !ruby/object:Gem::Requirement
185
+ requirements:
186
+ - - ">="
160
187
  - !ruby/object:Gem::Version
161
- version: '1.4'
188
+ version: '0'
189
+ type: :development
190
+ prerelease: false
191
+ version_requirements: !ruby/object:Gem::Requirement
192
+ requirements:
193
+ - - ">="
194
+ - !ruby/object:Gem::Version
195
+ version: '0'
162
196
  - !ruby/object:Gem::Dependency
163
197
  name: rspec-rails
164
198
  requirement: !ruby/object:Gem::Requirement
165
199
  requirements:
166
200
  - - "~>"
167
201
  - !ruby/object:Gem::Version
168
- version: '3.5'
202
+ version: '5.0'
169
203
  type: :development
170
204
  prerelease: false
171
205
  version_requirements: !ruby/object:Gem::Requirement
172
206
  requirements:
173
207
  - - "~>"
174
208
  - !ruby/object:Gem::Version
175
- version: '3.5'
209
+ version: '5.0'
176
210
  - !ruby/object:Gem::Dependency
177
211
  name: factory_bot_rails
178
212
  requirement: !ruby/object:Gem::Requirement
@@ -308,8 +342,10 @@ files:
308
342
  - app/models/ucb_rails_user/user_session_manager/base.rb
309
343
  - app/models/ucb_rails_user/user_session_manager/in_people_ou.rb
310
344
  - app/models/ucb_rails_user/user_session_manager/in_people_ou_add_to_users_table.rb
345
+ - app/models/ucb_rails_user/user_session_manager/in_uc_path_add_to_users_table.rb
311
346
  - app/models/ucb_rails_user/user_session_manager/ldap_person_user_wrapper.rb
312
347
  - app/models/ucb_rails_user/user_session_manager/test_session_manager.rb
348
+ - app/models/ucb_rails_user/user_uc_path_service.rb
313
349
  - app/models/user.rb
314
350
  - app/views/ucb_rails_user/home/logged_in.html.haml
315
351
  - app/views/ucb_rails_user/home/not_logged_in.html.haml
@@ -356,7 +392,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
356
392
  - !ruby/object:Gem::Version
357
393
  version: '0'
358
394
  requirements: []
359
- rubygems_version: 3.1.2
395
+ rubygems_version: 3.3.7
360
396
  signing_key:
361
397
  specification_version: 4
362
398
  summary: Rails engine for UCB user accounts