hubssolib 3.7.1 → 3.8.1
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +12 -1
- data/Gemfile.lock +164 -4
- data/README.md +21 -0
- data/hubssolib-3.7.0.gem +0 -0
- data/hubssolib.gemspec +2 -1
- data/lib/hub_sso_lib.rb +310 -123
- metadata +17 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5fea64186dc1f80987fb5b531c46ac8eb9fff78878520b38e392a91dad8de7a9
|
4
|
+
data.tar.gz: 2ebe2f6599cbd9bf9dbfbaa6ebbbb81e99fe6f4922c5f8c19e250e380222c3c9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 44b066f10c3615a752b258d85ccf5316358c33af6589c9702ab6b2ae8036f6e7eda9f99ab2a2707dc9acce9e9377ce5e73f28c3533eaec7c7312ac5e6e828fe3
|
7
|
+
data.tar.gz: 1f7ae4d9e29916eb3d14e3c057b61f95192be76954270fd8570dd596a5552495561df2bddd1f16f887ac613bbcd3292fd75228f4bbddf87faeda698c2a866067
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,14 @@
|
|
1
|
+
## 3.8.1, 09-Apr-2025
|
2
|
+
|
3
|
+
* It's been too long since I worked with DRb! Important fix for "live" (undumpable) vs copied objects which could lead to session enumeration problems in clients. Now, sessions enumerated by user ID are copies as is user data returned by HubSsoLib::Core#hubssolib_enumerate_users.
|
4
|
+
* Other data is still live, since there's a fair amount of write-back that expects to be updating objects held by the DRb server itself. This will all get replaced by database storage in HubSsoLib 4, so I'm not going to address the weaknesses present wherein a session might be expired or deleted "under the feet" of a client. The Hub gem's own write-based operations are all on a "current" session, so that could only vanish if an admin independently elected to destroy all user sessions via the Hub Rails app front-end. The implication is that the other user was probably up to no good, and I don't really mind if they just seem to be suddenly logged out, or see a 500 error due to a _very_ inconveniently-timed page fetch.
|
5
|
+
|
6
|
+
## 3.8.0, 03-Apr-2025
|
7
|
+
|
8
|
+
* Adds helper `HubSsoLib::Core#hubssolib_flash_markup` to compliment `HubSsoLib::Core#hubssolib_flash_data` and help make Flash presentation simpler and more consistent across integrated applications.
|
9
|
+
* Deprecates core methods `hubssolib_store_location` (which is now a no-op) and `hubssolib_redirect_back_or_default` (which now always redirects to the default location). **These methods will be removed in Hub 4**. Ephemeral return-to location storage has only worked when sessions are _on_, which once upon a time was always - logged in or not - but changed in Hub 3.4.0, to avoid very large numbers of anonymous sessions building up into a very RAM-hungry pools in the DRb server. This has in hindsight amounted to a breaking change, and I should've bumped to Hub 4 per SemVer at that time, but it was overlooked; apologies. At least in general all it really usually means is that, instead of redirecting back to some calling application after login, the user is left in their Hub account view.
|
10
|
+
* Hub's UI element added to navigation bars by using `HubSsoLib::Core#hubssolib_account_link` plus permissions and must-log-in checking in the `HubSsoLib::Core#hubssolib_beforehand` before-action callback already dealt with and continue to deal with redirect-to-origin automatically, so often, applications did't need to store a location and then manually redirect to Hub anyway. If you do need this for some reason, though, the new workflow is create a link or redirection to the URL returned by `HubSsoLib::Core#hubssolib_returnable_account_url`. This simply encodes a return-to address in the URL where needed, removing any requirement for cross-application session storage. The method's documentation describes its uses but, for the majority of use cases, you'll probably only want to be presenting a link for the case where a user must log _in_. In that case, call `hubssolib_returnable_account_url(logged_in: false)`.
|
11
|
+
|
1
12
|
## 3.7.0 and 3.7.1, 28-Mar-2025
|
2
13
|
|
3
14
|
* Login indicator cookie wasn't updated on session timeout, so when the page loaded for pages that do *not* require authorisation, the warning flash about being timed out would show, but the indicator would still show a "logged in" state until the next page fetch.
|
@@ -85,7 +96,7 @@ In Hub v1 and v2, login indication was done via an image that was served by the
|
|
85
96
|
|
86
97
|
```html
|
87
98
|
<a class="img" href="<%= ENV['HUB_PATH_PREFIX'] %>/account/login_conditional">
|
88
|
-
<img src="<%= ENV['HUB_PATH_PREFIX'] %>/account/login_indication" alt="Account" height="22" width="90"
|
99
|
+
<img src="<%= ENV['HUB_PATH_PREFIX'] %>/account/login_indication" alt="Account" height="22" width="90">
|
89
100
|
</a>
|
90
101
|
```
|
91
102
|
|
data/Gemfile.lock
CHANGED
@@ -1,14 +1,91 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
hubssolib (3.
|
4
|
+
hubssolib (3.8.1)
|
5
5
|
base64 (~> 0.2)
|
6
6
|
drb (~> 2.2)
|
7
7
|
|
8
8
|
GEM
|
9
9
|
remote: https://rubygems.org/
|
10
10
|
specs:
|
11
|
+
actioncable (8.0.2)
|
12
|
+
actionpack (= 8.0.2)
|
13
|
+
activesupport (= 8.0.2)
|
14
|
+
nio4r (~> 2.0)
|
15
|
+
websocket-driver (>= 0.6.1)
|
16
|
+
zeitwerk (~> 2.6)
|
17
|
+
actionmailbox (8.0.2)
|
18
|
+
actionpack (= 8.0.2)
|
19
|
+
activejob (= 8.0.2)
|
20
|
+
activerecord (= 8.0.2)
|
21
|
+
activestorage (= 8.0.2)
|
22
|
+
activesupport (= 8.0.2)
|
23
|
+
mail (>= 2.8.0)
|
24
|
+
actionmailer (8.0.2)
|
25
|
+
actionpack (= 8.0.2)
|
26
|
+
actionview (= 8.0.2)
|
27
|
+
activejob (= 8.0.2)
|
28
|
+
activesupport (= 8.0.2)
|
29
|
+
mail (>= 2.8.0)
|
30
|
+
rails-dom-testing (~> 2.2)
|
31
|
+
actionpack (8.0.2)
|
32
|
+
actionview (= 8.0.2)
|
33
|
+
activesupport (= 8.0.2)
|
34
|
+
nokogiri (>= 1.8.5)
|
35
|
+
rack (>= 2.2.4)
|
36
|
+
rack-session (>= 1.0.1)
|
37
|
+
rack-test (>= 0.6.3)
|
38
|
+
rails-dom-testing (~> 2.2)
|
39
|
+
rails-html-sanitizer (~> 1.6)
|
40
|
+
useragent (~> 0.16)
|
41
|
+
actiontext (8.0.2)
|
42
|
+
actionpack (= 8.0.2)
|
43
|
+
activerecord (= 8.0.2)
|
44
|
+
activestorage (= 8.0.2)
|
45
|
+
activesupport (= 8.0.2)
|
46
|
+
globalid (>= 0.6.0)
|
47
|
+
nokogiri (>= 1.8.5)
|
48
|
+
actionview (8.0.2)
|
49
|
+
activesupport (= 8.0.2)
|
50
|
+
builder (~> 3.1)
|
51
|
+
erubi (~> 1.11)
|
52
|
+
rails-dom-testing (~> 2.2)
|
53
|
+
rails-html-sanitizer (~> 1.6)
|
54
|
+
activejob (8.0.2)
|
55
|
+
activesupport (= 8.0.2)
|
56
|
+
globalid (>= 0.3.6)
|
57
|
+
activemodel (8.0.2)
|
58
|
+
activesupport (= 8.0.2)
|
59
|
+
activerecord (8.0.2)
|
60
|
+
activemodel (= 8.0.2)
|
61
|
+
activesupport (= 8.0.2)
|
62
|
+
timeout (>= 0.4.0)
|
63
|
+
activestorage (8.0.2)
|
64
|
+
actionpack (= 8.0.2)
|
65
|
+
activejob (= 8.0.2)
|
66
|
+
activerecord (= 8.0.2)
|
67
|
+
activesupport (= 8.0.2)
|
68
|
+
marcel (~> 1.0)
|
69
|
+
activesupport (8.0.2)
|
70
|
+
base64
|
71
|
+
benchmark (>= 0.3)
|
72
|
+
bigdecimal
|
73
|
+
concurrent-ruby (~> 1.0, >= 1.3.1)
|
74
|
+
connection_pool (>= 2.2.5)
|
75
|
+
drb
|
76
|
+
i18n (>= 1.6, < 2)
|
77
|
+
logger (>= 1.4.2)
|
78
|
+
minitest (>= 5.1)
|
79
|
+
securerandom (>= 0.3)
|
80
|
+
tzinfo (~> 2.0, >= 2.0.5)
|
81
|
+
uri (>= 0.13.1)
|
11
82
|
base64 (0.2.0)
|
83
|
+
benchmark (0.4.0)
|
84
|
+
bigdecimal (3.1.9)
|
85
|
+
builder (3.3.0)
|
86
|
+
concurrent-ruby (1.3.5)
|
87
|
+
connection_pool (2.5.0)
|
88
|
+
crass (1.0.6)
|
12
89
|
date (3.4.1)
|
13
90
|
debug (1.10.0)
|
14
91
|
irb (~> 1.10)
|
@@ -18,20 +95,90 @@ GEM
|
|
18
95
|
doggo (1.4.0)
|
19
96
|
rspec-core (~> 3.13)
|
20
97
|
drb (2.2.1)
|
98
|
+
erubi (1.13.1)
|
99
|
+
globalid (1.2.1)
|
100
|
+
activesupport (>= 6.1)
|
101
|
+
i18n (1.14.7)
|
102
|
+
concurrent-ruby (~> 1.0)
|
21
103
|
io-console (0.8.0)
|
22
|
-
irb (1.15.
|
104
|
+
irb (1.15.2)
|
23
105
|
pp (>= 0.6.0)
|
24
106
|
rdoc (>= 4.0.0)
|
25
107
|
reline (>= 0.4.2)
|
108
|
+
logger (1.7.0)
|
109
|
+
loofah (2.24.0)
|
110
|
+
crass (~> 1.0.2)
|
111
|
+
nokogiri (>= 1.12.0)
|
112
|
+
mail (2.8.1)
|
113
|
+
mini_mime (>= 0.1.1)
|
114
|
+
net-imap
|
115
|
+
net-pop
|
116
|
+
net-smtp
|
117
|
+
marcel (1.0.4)
|
118
|
+
mini_mime (1.1.5)
|
119
|
+
mini_portile2 (2.8.8)
|
120
|
+
minitest (5.25.5)
|
121
|
+
net-imap (0.5.6)
|
122
|
+
date
|
123
|
+
net-protocol
|
124
|
+
net-pop (0.1.2)
|
125
|
+
net-protocol
|
126
|
+
net-protocol (0.2.2)
|
127
|
+
timeout
|
128
|
+
net-smtp (0.5.1)
|
129
|
+
net-protocol
|
130
|
+
nio4r (2.7.4)
|
131
|
+
nokogiri (1.18.7)
|
132
|
+
mini_portile2 (~> 2.8.2)
|
133
|
+
racc (~> 1.4)
|
26
134
|
pp (0.6.2)
|
27
135
|
prettyprint
|
28
136
|
prettyprint (0.2.0)
|
29
137
|
psych (5.2.3)
|
30
138
|
date
|
31
139
|
stringio
|
32
|
-
|
140
|
+
racc (1.8.1)
|
141
|
+
rack (3.1.12)
|
142
|
+
rack-session (2.1.0)
|
143
|
+
base64 (>= 0.1.0)
|
144
|
+
rack (>= 3.0.0)
|
145
|
+
rack-test (2.2.0)
|
146
|
+
rack (>= 1.3)
|
147
|
+
rackup (2.2.1)
|
148
|
+
rack (>= 3)
|
149
|
+
rails (8.0.2)
|
150
|
+
actioncable (= 8.0.2)
|
151
|
+
actionmailbox (= 8.0.2)
|
152
|
+
actionmailer (= 8.0.2)
|
153
|
+
actionpack (= 8.0.2)
|
154
|
+
actiontext (= 8.0.2)
|
155
|
+
actionview (= 8.0.2)
|
156
|
+
activejob (= 8.0.2)
|
157
|
+
activemodel (= 8.0.2)
|
158
|
+
activerecord (= 8.0.2)
|
159
|
+
activestorage (= 8.0.2)
|
160
|
+
activesupport (= 8.0.2)
|
161
|
+
bundler (>= 1.15.0)
|
162
|
+
railties (= 8.0.2)
|
163
|
+
rails-dom-testing (2.2.0)
|
164
|
+
activesupport (>= 5.0.0)
|
165
|
+
minitest
|
166
|
+
nokogiri (>= 1.6)
|
167
|
+
rails-html-sanitizer (1.6.2)
|
168
|
+
loofah (~> 2.21)
|
169
|
+
nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0)
|
170
|
+
railties (8.0.2)
|
171
|
+
actionpack (= 8.0.2)
|
172
|
+
activesupport (= 8.0.2)
|
173
|
+
irb (~> 1.13)
|
174
|
+
rackup (>= 1.0.0)
|
175
|
+
rake (>= 12.2)
|
176
|
+
thor (~> 1.0, >= 1.2.2)
|
177
|
+
zeitwerk (~> 2.6)
|
178
|
+
rake (13.2.1)
|
179
|
+
rdoc (6.13.1)
|
33
180
|
psych (>= 4.0.0)
|
34
|
-
reline (0.6.
|
181
|
+
reline (0.6.1)
|
35
182
|
io-console (~> 0.5)
|
36
183
|
rspec (3.13.0)
|
37
184
|
rspec-core (~> 3.13.0)
|
@@ -46,6 +193,7 @@ GEM
|
|
46
193
|
diff-lcs (>= 1.2.0, < 2.0)
|
47
194
|
rspec-support (~> 3.13.0)
|
48
195
|
rspec-support (3.13.2)
|
196
|
+
securerandom (0.4.1)
|
49
197
|
simplecov (0.22.0)
|
50
198
|
docile (~> 1.1)
|
51
199
|
simplecov-html (~> 0.11)
|
@@ -53,6 +201,17 @@ GEM
|
|
53
201
|
simplecov-html (0.13.1)
|
54
202
|
simplecov_json_formatter (0.1.4)
|
55
203
|
stringio (3.1.6)
|
204
|
+
thor (1.3.2)
|
205
|
+
timeout (0.4.3)
|
206
|
+
tzinfo (2.0.6)
|
207
|
+
concurrent-ruby (~> 1.0)
|
208
|
+
uri (1.0.3)
|
209
|
+
useragent (0.16.11)
|
210
|
+
websocket-driver (0.7.7)
|
211
|
+
base64
|
212
|
+
websocket-extensions (>= 0.1.0)
|
213
|
+
websocket-extensions (0.1.5)
|
214
|
+
zeitwerk (2.7.2)
|
56
215
|
|
57
216
|
PLATFORMS
|
58
217
|
ruby
|
@@ -61,6 +220,7 @@ DEPENDENCIES
|
|
61
220
|
debug (~> 1.1)
|
62
221
|
doggo (~> 1.4)
|
63
222
|
hubssolib!
|
223
|
+
rails (~> 8.0)
|
64
224
|
rspec (~> 3.13)
|
65
225
|
rspec-mocks (~> 3.13)
|
66
226
|
simplecov (~> 0.22)
|
data/README.md
CHANGED
@@ -449,4 +449,25 @@ end
|
|
449
449
|
* Your previously submitted action scheme and URL are also given in case you need them because you've decided to implement one callback handler for different kinds of untrusted action.
|
450
450
|
* The `action_payload` is where all your important data, meaningful only to you, resides and this must contain everything else, other than the above parameters, required to complete the action previously sent for review, _while making sure things are attributed to the correct user_.
|
451
451
|
|
452
|
+
Use `head ...` to indicate non-200 responses. If you don't want the originating user to get notified of a successful run, then on-success, also reply with `head :ok` or `head 200` (according to style preference). If you want to ask Hub to notify the user, then on-success instead do this:
|
453
|
+
|
454
|
+
```ruby
|
455
|
+
render json: { mail_item_url: ..., mail_subject: ... }, status: :ok
|
456
|
+
```
|
457
|
+
|
458
|
+
The payload items shown above are both mandatory:
|
459
|
+
|
460
|
+
* `mail_item_url` is the full URL of the entity that you just successfully edited, updated, or some other sensible URL to take the user (this will be included verbatim in the e-mail)
|
461
|
+
* `mail_subject` is a subject line of your choosing - for example, `"Your new forum post is now visible"`. Hub might add a prefix such as `[ORGNAME] ...`
|
462
|
+
|
463
|
+
If either item is missing or blank, or if for any reason Hub finds itself unable to associated the action with a user record on Hub's side, then no e-mail message will be sent.
|
464
|
+
|
465
|
+
**IMPORTANT:** The Hub application's database migration at the time you updated to 3.7.0 will have set existing users to trusted for historic data, but new users are untrusted. If you introduce trust integration to your site's other apps after this, you might want to enter the console to update any new users added since likewise; inside `app/hub`, issue:
|
466
|
+
|
467
|
+
```
|
468
|
+
$ bundle exec rails c
|
469
|
+
> User.update_all(trusted: true)
|
470
|
+
> exit
|
471
|
+
```
|
472
|
+
|
452
473
|
The trust mechanism involves a fair amount of effort on the integrating app's side but it can be very useful if you have a site where, despite your best efforts, sometimes spam/bot accounts manage to get inside and try to flood the system with spam. It's just one of many different potential protection and mitigation mechanisms that your site might choose to employ.
|
data/hubssolib-3.7.0.gem
ADDED
Binary file
|
data/hubssolib.gemspec
CHANGED
@@ -4,7 +4,7 @@ spec = Gem::Specification.new do |s|
|
|
4
4
|
s.platform = Gem::Platform::RUBY
|
5
5
|
s.name = 'hubssolib'
|
6
6
|
|
7
|
-
s.version = '3.
|
7
|
+
s.version = '3.8.1'
|
8
8
|
s.author = 'Andrew Hodgkinson and others'
|
9
9
|
s.email = 'ahodgkin@rowing.org.uk'
|
10
10
|
s.homepage = 'http://pond.org.uk/'
|
@@ -28,6 +28,7 @@ spec = Gem::Specification.new do |s|
|
|
28
28
|
s.add_dependency 'base64', '~> 0.2'
|
29
29
|
|
30
30
|
s.add_development_dependency 'debug', '~> 1.1'
|
31
|
+
s.add_development_dependency 'rails', '~> 8.0'
|
31
32
|
s.add_development_dependency 'simplecov', '~> 0.22'
|
32
33
|
s.add_development_dependency 'doggo', '~> 1.4'
|
33
34
|
s.add_development_dependency 'rspec', '~> 3.13'
|
data/lib/hub_sso_lib.rb
CHANGED
@@ -69,7 +69,7 @@ module HubSsoLib
|
|
69
69
|
|
70
70
|
# Location of Hub application root.
|
71
71
|
#
|
72
|
-
HUB_PATH_PREFIX = ENV['HUB_PATH_PREFIX'] || ''
|
72
|
+
HUB_PATH_PREFIX = (ENV['HUB_PATH_PREFIX'] || '').sub(/(\/)+$/, '')
|
73
73
|
|
74
74
|
# Time limit, *in seconds*, for the account inactivity timeout. If a user
|
75
75
|
# performs no Hub actions during this time they will be automatically logged
|
@@ -366,17 +366,16 @@ module HubSsoLib
|
|
366
366
|
# 26-Feb-2025 (ADH): Add 'trusted' concept. #
|
367
367
|
#######################################################################
|
368
368
|
|
369
|
+
# This *must not* be 'undumped', since it gets passed from clients back to
|
370
|
+
# the persistent DRb server process. A client thread may disappear and be
|
371
|
+
# recreated by the web server at any time; if the user object is undumpable,
|
372
|
+
# then the DRb server has to *call back to the client* (in DRb, clients are
|
373
|
+
# also servers...!) to find out about the object. Trouble is, if the client
|
374
|
+
# thread has been recreated, the server will be trying to access to stale
|
375
|
+
# objects that only exist if the garbage collector hasn't got to them yet.
|
376
|
+
#
|
369
377
|
class User
|
370
378
|
|
371
|
-
# This *must not* be 'undumped', since it gets passed from clients
|
372
|
-
# back to the persistent DRb server process. A client thread may
|
373
|
-
# disappear and be recreated by the web server at any time; if the
|
374
|
-
# user object is undumpable, then the DRb server has to *call back
|
375
|
-
# to the client* (in DRb, clients are also servers...!) to find out
|
376
|
-
# about the object. Trouble is, if the client thread has been
|
377
|
-
# recreated, the server will be trying to access to stale objects
|
378
|
-
# that only exist if the garbage collector hasn't got to them yet.
|
379
|
-
|
380
379
|
attr_accessor :user_salt
|
381
380
|
attr_accessor :user_roles
|
382
381
|
attr_accessor :user_updated_at
|
@@ -394,29 +393,11 @@ module HubSsoLib
|
|
394
393
|
attr_accessor :user_password_reset_code_expires_at
|
395
394
|
attr_accessor :user_trusted
|
396
395
|
|
397
|
-
def initialize
|
398
|
-
@user_salt = nil
|
399
|
-
@user_roles = nil
|
400
|
-
@user_updated_at = nil
|
401
|
-
@user_activated_at = nil
|
402
|
-
@user_real_name = nil
|
403
|
-
@user_crypted_password = nil
|
404
|
-
@user_remember_token_expires_at = nil
|
405
|
-
@user_activation_code = nil
|
406
|
-
@user_member_id = nil
|
407
|
-
@user_id = nil
|
408
|
-
@user_password_reset_code = nil
|
409
|
-
@user_remember_token = nil
|
410
|
-
@user_email = nil
|
411
|
-
@user_created_at = nil
|
412
|
-
@user_password_reset_code_expires_at = nil
|
413
|
-
@user_trusted = nil
|
414
|
-
end
|
415
396
|
end # User class
|
416
397
|
|
417
398
|
#######################################################################
|
418
|
-
# Class: Session
|
419
|
-
# (C) Hipposoft 2006
|
399
|
+
# Class: Session family #
|
400
|
+
# (C) Hipposoft 2006-2025 #
|
420
401
|
# #
|
421
402
|
# Purpose: Session support object, used to store session metadata in #
|
422
403
|
# an insecure cross-application cookie. #
|
@@ -424,37 +405,67 @@ module HubSsoLib
|
|
424
405
|
# Author: A.D.Hodgkinson #
|
425
406
|
# #
|
426
407
|
# History: 22-Oct-2006 (ADH): Created. #
|
408
|
+
# 09-Apr-2025 (ADH): Dumpable/undumpable variants created. #
|
427
409
|
#######################################################################
|
428
410
|
|
429
|
-
class
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
411
|
+
# A dumpable base class that can be used for undumpable proxies, where a
|
412
|
+
# change made in an object passed to a client is reflected on the server
|
413
|
+
# where the object actually lives; or for dumpable clones of sessions sent
|
414
|
+
# as read-only copies to clients which won't disppear due to server side
|
415
|
+
# deletion from key rotation, expiry or admin-driven deletion.
|
416
|
+
#
|
417
|
+
class SessionBase
|
418
|
+
|
419
|
+
ATTRIBUTES = %i{
|
420
|
+
session_last_used
|
421
|
+
session_flash
|
422
|
+
session_user
|
423
|
+
session_rotated_key
|
424
|
+
}
|
425
|
+
|
426
|
+
ATTRIBUTES.each { | attr | attr_accessor(attr) }
|
427
|
+
attr_reader :session_return_to # DEPRECATED
|
428
|
+
|
429
|
+
def initialize(copying_session: nil)
|
430
|
+
if copying_session.nil?
|
431
|
+
self.session_last_used = Time.now.utc
|
432
|
+
self.session_flash = {}
|
433
|
+
self.session_user = HubSsoLib::User.new
|
434
|
+
self.session_rotated_key = nil
|
435
|
+
else
|
436
|
+
ATTRIBUTES.each do | attr |
|
437
|
+
self.send("#{attr}=", copying_session.send(attr))
|
438
|
+
end
|
439
|
+
end
|
451
440
|
|
452
441
|
rescue => e
|
453
442
|
Sentry.capture_exception(e) if defined?(Sentry) && Sentry.respond_to?(:capture_exception)
|
454
443
|
raise
|
455
444
|
end
|
445
|
+
|
446
|
+
end # SessionBase class
|
447
|
+
|
448
|
+
# Unlike a User, this *is* undumpable since it only gets passed from server
|
449
|
+
# to client. The server's always here to service requests from the client and
|
450
|
+
# used sessions are never garbage collected since the DRb server's front
|
451
|
+
# object, a SessionFactory, keeps them in a hash held within an instance
|
452
|
+
# variable.
|
453
|
+
#
|
454
|
+
# A recognised weakness here is that a session might disappear from under the
|
455
|
+
# feet of an accessing application, due to key rotation or explicit deletion.
|
456
|
+
#
|
457
|
+
class Session < SessionBase
|
458
|
+
include DRb::DRbUndumped
|
456
459
|
end # Session class
|
457
460
|
|
461
|
+
# No special conditions - this is just a dumpable session. You should usually
|
462
|
+
# create it based on an undumpable, 'live' session thus:
|
463
|
+
#
|
464
|
+
# SessionCopy.new(copying_session: undumpable_session)
|
465
|
+
#
|
466
|
+
class SessionCopy < SessionBase
|
467
|
+
end # SessionCopy class
|
468
|
+
|
458
469
|
#######################################################################
|
459
470
|
# Class: SessionFactory #
|
460
471
|
# (C) Hipposoft 2006 #
|
@@ -613,7 +624,9 @@ module HubSsoLib
|
|
613
624
|
keys = if count > HUB_SESSION_ENUMERATION_KEY_MAX
|
614
625
|
nil
|
615
626
|
else
|
616
|
-
|
627
|
+
HUB_MUTEX.synchronize do
|
628
|
+
@hub_sessions.keys # (Hash#keys returns a new array)
|
629
|
+
end
|
617
630
|
end
|
618
631
|
|
619
632
|
return { count: count, keys: keys }
|
@@ -627,8 +640,18 @@ module HubSsoLib
|
|
627
640
|
# given session key. No key rotation occurs. Returns +nil+ if no entry is
|
628
641
|
# found for that key.
|
629
642
|
#
|
643
|
+
# This returns a *LIVE OBJECT* owned by the DRb server. Writes made to this
|
644
|
+
# object will affect the live session state. However, the session might be
|
645
|
+
# invalidated at any time by actions such as key rotation, expiration or
|
646
|
+
# explicit user deletion. Attempts to read or write properties would then
|
647
|
+
# lead to exceptions such as:
|
648
|
+
#
|
649
|
+
# "424" is not id value (RangeError)
|
650
|
+
#
|
651
|
+
# ...where 424 is the internal object ID of meaning only to the DRb system.
|
652
|
+
#
|
630
653
|
def retrieve_session_by_key(key)
|
631
|
-
@hub_sessions[key]
|
654
|
+
HUB_MUTEX.synchronize { @hub_sessions[key] }
|
632
655
|
end
|
633
656
|
|
634
657
|
# WARNING: Comparatively slow.
|
@@ -638,15 +661,24 @@ module HubSsoLib
|
|
638
661
|
# values yielding HubSsoLib::Session instances as values is returned.
|
639
662
|
#
|
640
663
|
# The array is ordered by least-recently-active first to most-recent last.
|
664
|
+
# Returned data is a copy of internal session information and should be
|
665
|
+
# considered read-only; changes made will have no effect outside your own
|
666
|
+
# application.
|
641
667
|
#
|
642
668
|
# IN THE CURRENT IMPLEMENTATION THIS JUST SEQUENTIALLY SCANS ALL ACTIVE
|
643
669
|
# SESSIONS IN THE HASH and must therefore lock on mutex for the duration.
|
644
670
|
#
|
645
671
|
def retrieve_sessions_by_user_id(user_id)
|
646
672
|
HUB_MUTEX.synchronize do
|
647
|
-
|
648
|
-
|
673
|
+
collection = {}
|
674
|
+
|
675
|
+
@hub_sessions.each do | key, session |
|
676
|
+
if session&.session_user&.user_id == user_id
|
677
|
+
collection[key] = SessionCopy.new(copying_session: session)
|
678
|
+
end
|
649
679
|
end
|
680
|
+
|
681
|
+
collection
|
650
682
|
end
|
651
683
|
end
|
652
684
|
|
@@ -655,10 +687,16 @@ module HubSsoLib
|
|
655
687
|
# session data. Does nothing if the key is not found.
|
656
688
|
#
|
657
689
|
def destroy_session_by_key(key)
|
690
|
+
unless @hub_be_quiet
|
691
|
+
puts "Session factory: Deleting session with key #{key}"
|
692
|
+
end
|
693
|
+
|
658
694
|
HUB_MUTEX.synchronize do
|
659
695
|
@hub_sessions.delete(key)
|
660
696
|
end
|
661
697
|
|
698
|
+
return nil
|
699
|
+
|
662
700
|
rescue => e
|
663
701
|
Sentry.capture_exception(e) if defined?(Sentry) && Sentry.respond_to?(:capture_exception)
|
664
702
|
raise
|
@@ -674,12 +712,44 @@ module HubSsoLib
|
|
674
712
|
# SESSIONS IN THE HASH and must therefore lock on mutex for the duration.
|
675
713
|
#
|
676
714
|
def destroy_sessions_by_user_id(user_id)
|
715
|
+
unless @hub_be_quiet
|
716
|
+
puts "Session factory: Deleting all session records for user ID #{user_id.inspect}"
|
717
|
+
end
|
718
|
+
|
677
719
|
HUB_MUTEX.synchronize do
|
678
720
|
@hub_sessions.reject! do | key, session |
|
679
721
|
session&.session_user&.user_id == user_id
|
680
722
|
end
|
681
723
|
end
|
682
724
|
|
725
|
+
return nil
|
726
|
+
|
727
|
+
rescue => e
|
728
|
+
Sentry.capture_exception(e) if defined?(Sentry) && Sentry.respond_to?(:capture_exception)
|
729
|
+
raise
|
730
|
+
end
|
731
|
+
|
732
|
+
# WARNING: Comparatively slow.
|
733
|
+
#
|
734
|
+
# Call only if you MUST update details of a session user inside all Hub
|
735
|
+
# sessions. Pass the user ID and HubSsoLib::User details that are to be
|
736
|
+
# stored for all sessions owned by that user ID.
|
737
|
+
#
|
738
|
+
def update_sessions_by_user_id(user_id, user)
|
739
|
+
unless @hub_be_quiet
|
740
|
+
puts "Session factory: Updating all session records for user ID #{user_id.inspect}"
|
741
|
+
end
|
742
|
+
|
743
|
+
HUB_MUTEX.synchronize do
|
744
|
+
@hub_sessions.each do | key, session |
|
745
|
+
if session&.session_user&.user_id == user_id
|
746
|
+
session.session_user = user
|
747
|
+
end
|
748
|
+
end
|
749
|
+
end
|
750
|
+
|
751
|
+
return nil
|
752
|
+
|
683
753
|
rescue => e
|
684
754
|
Sentry.capture_exception(e) if defined?(Sentry) && Sentry.respond_to?(:capture_exception)
|
685
755
|
raise
|
@@ -722,6 +792,8 @@ module HubSsoLib
|
|
722
792
|
puts "Session factory: ...Destroyed #{destroyed} session(s)"
|
723
793
|
end
|
724
794
|
|
795
|
+
return nil
|
796
|
+
|
725
797
|
rescue => e
|
726
798
|
Sentry.capture_exception(e) if defined?(Sentry) && Sentry.respond_to?(:capture_exception)
|
727
799
|
raise
|
@@ -964,34 +1036,97 @@ module HubSsoLib
|
|
964
1036
|
end
|
965
1037
|
end
|
966
1038
|
|
967
|
-
#
|
968
|
-
#
|
969
|
-
#
|
970
|
-
#
|
1039
|
+
# Return a URL that leads to a Hub "log in" page if the user is not logged
|
1040
|
+
# in currently, else an "account" page for logged-in users.
|
1041
|
+
#
|
1042
|
+
# +universal+:: Use +true+ if concerned that a "Back" browser button action
|
1043
|
+
# might cause a page to appear that's got a cached link which
|
1044
|
+
# may no longer reflect the current state. This jumps to Hub
|
1045
|
+
# and redirects to the "log in" or "account" destinations
|
1046
|
+
# depending on current state. If using this, bear in mind
|
1047
|
+
# that the link text must be ambiguous, because the eventual
|
1048
|
+
# destination isn't known.
|
1049
|
+
#
|
1050
|
+
# It's often better to just use #hubssolib_account_link to
|
1051
|
+
# create markup for this in a navigation area.
|
1052
|
+
#
|
1053
|
+
# The default is +false+, which means that a bespoke link
|
1054
|
+
# for the exact current instantaneous log in state is
|
1055
|
+
# generated; the +logged_in+ parameter applies (see below).
|
1056
|
+
#
|
1057
|
+
# +logged_in+:: If +universal+ is +false+, then this parameter defaults to
|
1058
|
+
# the current user logged-in state, but can be overridden
|
1059
|
+
# with +true+ (act as if someone is logged in) or +false+
|
1060
|
+
# (act as if someone is not logged in).
|
1061
|
+
#
|
1062
|
+
# +return_to+:: Overrides the use of <tt>request.original_url</tt> to give
|
1063
|
+
# an alternative return-after-logging-in URL. Will be of no
|
1064
|
+
# use for users already logged in. This is rarely used, but
|
1065
|
+
# might be helpful if you (say) want them to return to the
|
1066
|
+
# current page, but with a specific fragment added ("#foo").
|
1067
|
+
# Specify as a String, Symbol or URI, at your preference.
|
1068
|
+
#
|
1069
|
+
# Note that the universal links, or a not-logged-in state link will include
|
1070
|
+
# a query string which takes the value of <tt>request.original_url</tt> or,
|
1071
|
+
# if not defined, tries <tt>request.referrer</tt> (else is absent). This is
|
1072
|
+
# a URL used for the redirection after successful login. The logged-in
|
1073
|
+
# state link does not require this addition so omits it for brevity.
|
1074
|
+
#
|
1075
|
+
def hubssolib_returnable_account_url(
|
1076
|
+
universal: false,
|
1077
|
+
logged_in: self.hubssolib_logged_in?,
|
1078
|
+
return_to: nil
|
1079
|
+
)
|
1080
|
+
account_url = if universal
|
1081
|
+
"#{HUB_PATH_PREFIX}/account/login_conditional"
|
1082
|
+
else
|
1083
|
+
"#{HUB_PATH_PREFIX}/#{'account/login' unless logged_in}"
|
1084
|
+
end
|
1085
|
+
|
1086
|
+
# Attach a return-to URL always for the universal case which needs to
|
1087
|
+
# work regardless of login state; else we only need it when logged out,
|
1088
|
+
# so that we can return to the originating location after logging in.
|
1089
|
+
# There's no functional difference - just a simpler URL that omits what
|
1090
|
+
# would otherwise be an unused query string parameter.
|
1091
|
+
#
|
1092
|
+
if universal or not logged_in
|
1093
|
+
if return_to.nil?
|
1094
|
+
request_obj = self.try(:request)
|
1095
|
+
return_to = request_obj.try(:original_url) || request_obj.try(:referrer)
|
1096
|
+
end
|
1097
|
+
|
1098
|
+
if return_to.present?
|
1099
|
+
account_url << "?return_to_url=#{CGI.escape(return_to.to_s)}"
|
1100
|
+
end
|
1101
|
+
end
|
1102
|
+
|
1103
|
+
return account_url
|
1104
|
+
end
|
1105
|
+
|
1106
|
+
# Returns markup for a link that leads to Hub's login or logout link, using
|
1107
|
+
# pure HTML + CSS for styling. A universal "conditional login" link is used
|
1108
|
+
# since page data may be old due to e.g. a "back" button being used, after
|
1109
|
+
# the user either logged in or out elsewhere. This possibility is also why
|
1110
|
+
# JavaScript is used, updating the button styling the correct login state
|
1111
|
+
# if needed. This requires the "pageshow" event to be supported. NOSCRIPT
|
1112
|
+
# browsers use the a no-cache image-based fallback, which is much less
|
1113
|
+
# efficient, but works.
|
971
1114
|
#
|
972
|
-
#
|
973
|
-
#
|
974
|
-
#
|
975
|
-
# no-cache image fallback, which is much less efficient, but works.
|
1115
|
+
# Although the JavaScript-powered option could use the non-conditional link
|
1116
|
+
# for log in/out and swap those, it's simpler just to use generate the same
|
1117
|
+
# link for all states - script-capable or otherwise, logged in or out,
|
976
1118
|
#
|
977
1119
|
def hubssolib_account_link
|
978
|
-
|
979
|
-
|
1120
|
+
logged_in_url = self.hubssolib_returnable_account_url(universal: false, logged_in: true)
|
1121
|
+
logged_out_url = self.hubssolib_returnable_account_url(universal: false, logged_in: false)
|
1122
|
+
universal_url = self.hubssolib_returnable_account_url(universal: true)
|
1123
|
+
|
980
1124
|
noscript_img_src = "#{HUB_PATH_PREFIX}/account/login_indication.png"
|
981
1125
|
noscript_img_tag = helpers.image_tag(noscript_img_src, size: '90x22', border: '0', alt: 'Log in or out')
|
982
1126
|
|
983
|
-
|
984
|
-
|
985
|
-
|
986
|
-
if return_to_url.present?
|
987
|
-
return_query = URI.encode_www_form({ return_to_url: return_to_url.to_s })
|
988
|
-
ui_href << "?#{return_query}"
|
989
|
-
end
|
990
|
-
end
|
991
|
-
|
992
|
-
logged_in_link = helpers.link_to('Account', ui_href, id: 'hubssolib_logged_in_link')
|
993
|
-
logged_out_link = helpers.link_to('Log in', ui_href, id: 'hubssolib_logged_out_link')
|
994
|
-
noscript_link = helpers.link_to(noscript_img_tag, ui_href, id: 'hubssolib_login_noscript')
|
1127
|
+
logged_in_link = helpers.link_to('Account', logged_in_url, id: 'hubssolib_logged_in_link')
|
1128
|
+
logged_out_link = helpers.link_to('Log in', logged_out_url, id: 'hubssolib_logged_out_link')
|
1129
|
+
noscript_link = helpers.link_to(noscript_img_tag, universal_url, id: 'hubssolib_login_noscript')
|
995
1130
|
|
996
1131
|
# Yes, it's ugly, but yes, it works and it's a lot better for the server
|
997
1132
|
# to avoid the repeated image fetches. It probably works out as overall
|
@@ -1172,8 +1307,8 @@ module HubSsoLib
|
|
1172
1307
|
|
1173
1308
|
unless hub_session_info[:keys].nil? # (keyset too large, enumeration prohibited)
|
1174
1309
|
hub_session_info[:keys].each do | key |
|
1175
|
-
|
1176
|
-
hub_users <<
|
1310
|
+
session_user = hubssolib_factory().retrieve_session_by_key(key)&.session_user
|
1311
|
+
hub_users << session_user unless session_user&.user_id.nil?
|
1177
1312
|
end
|
1178
1313
|
end
|
1179
1314
|
|
@@ -1217,6 +1352,18 @@ module HubSsoLib
|
|
1217
1352
|
hubssolib_factory().destroy_sessions_by_user_id(hub_user_id) unless hub_user_id.nil?
|
1218
1353
|
end
|
1219
1354
|
|
1355
|
+
# WARNING: Comparatively slow.
|
1356
|
+
#
|
1357
|
+
# If a Hub user record changes, make sure their session records reflect
|
1358
|
+
# the updated demographics according to the HubSsoLib::User provided.
|
1359
|
+
#
|
1360
|
+
# For information about performance limitations, see
|
1361
|
+
# HubSsoLib::SessionFactory#destroy_sessions_by_user_id.
|
1362
|
+
#
|
1363
|
+
def hubssolib_update_user_sessions(hub_user_id, hub_user)
|
1364
|
+
hubssolib_factory().update_sessions_by_user_id(hub_user_id, hub_user) unless hub_user_id.nil?
|
1365
|
+
end
|
1366
|
+
|
1220
1367
|
# If an application needs to know about changes of a user e-mail address
|
1221
1368
|
# or display name (e.g. because of sync to a local relational store of
|
1222
1369
|
# users related to other application-managed resources, with therefore a
|
@@ -1327,7 +1474,6 @@ module HubSsoLib
|
|
1327
1474
|
cookies.delete(HUB_LOGIN_INDICATOR_COOKIE, domain: :all, path: '/')
|
1328
1475
|
|
1329
1476
|
if login_is_required
|
1330
|
-
hubssolib_store_location()
|
1331
1477
|
return hubssolib_must_login()
|
1332
1478
|
else
|
1333
1479
|
return true
|
@@ -1354,14 +1500,10 @@ module HubSsoLib
|
|
1354
1500
|
# if OK, else indicate that access is denied.
|
1355
1501
|
|
1356
1502
|
if (hubssolib_session_expired?)
|
1357
|
-
hubssolib_store_location()
|
1358
1503
|
hubssolib_log_out()
|
1359
1504
|
hubssolib_set_flash(:attention, 'Sorry, your session timed out; you need to log in again to continue.')
|
1360
1505
|
|
1361
|
-
|
1362
|
-
# ...except for the Hub, rather than the current application (whatever
|
1363
|
-
# it may be).
|
1364
|
-
redirect_to HUB_PATH_PREFIX + '/account/login'
|
1506
|
+
redirect_to hubssolib_returnable_account_url(logged_in: false)
|
1365
1507
|
else
|
1366
1508
|
hubssolib_set_last_used(Time.now.utc)
|
1367
1509
|
return hubssolib_authorized? ? true : hubssolib_access_denied()
|
@@ -1410,28 +1552,17 @@ module HubSsoLib
|
|
1410
1552
|
end
|
1411
1553
|
end
|
1412
1554
|
|
1413
|
-
#
|
1414
|
-
# optional supplied specific URI.
|
1415
|
-
#
|
1416
|
-
# We can return to this location by calling #redirect_back_or_default.
|
1555
|
+
# Deprecated. Don't use this. See #hubssolib_returnable_account_url.
|
1417
1556
|
#
|
1418
1557
|
def hubssolib_store_location(uri_str = request.url)
|
1419
|
-
|
1420
|
-
uri_str = hubssolib_promote_uri_to_ssl(uri_str, request.host) unless request.ssl?
|
1421
|
-
hubssolib_set_return_to(uri_str)
|
1422
|
-
else
|
1423
|
-
hubssolib_set_return_to(nil)
|
1424
|
-
end
|
1558
|
+
Rails.logger.warn('hubssolib_store_location: DEPRECATED (no-op)') rescue nil
|
1425
1559
|
end
|
1426
1560
|
|
1427
|
-
#
|
1428
|
-
# to the passed default.
|
1561
|
+
# Deprecated. Don't use this. See #hubssolib_returnable_account_url.
|
1429
1562
|
#
|
1430
1563
|
def hubssolib_redirect_back_or_default(default)
|
1431
|
-
|
1432
|
-
|
1433
|
-
|
1434
|
-
redirect_to(url || default)
|
1564
|
+
Rails.logger.warn('hubssolib_redirect_back_or_default: DEPRECATED (always redirects to default)') rescue nil
|
1565
|
+
redirect_to(default)
|
1435
1566
|
end
|
1436
1567
|
|
1437
1568
|
# Take a URI and pass an optional host parameter. Decomposes the URI,
|
@@ -1440,9 +1571,10 @@ module HubSsoLib
|
|
1440
1571
|
# as a flat string.
|
1441
1572
|
#
|
1442
1573
|
def hubssolib_promote_uri_to_ssl(uri_str, host = nil)
|
1443
|
-
uri
|
1444
|
-
uri.host
|
1574
|
+
uri = URI.parse(uri_str)
|
1575
|
+
uri.host = host if host
|
1445
1576
|
uri.scheme = hub_bypass_ssl? ? 'http' : 'https'
|
1577
|
+
|
1446
1578
|
return uri.to_s
|
1447
1579
|
end
|
1448
1580
|
|
@@ -1454,8 +1586,7 @@ module HubSsoLib
|
|
1454
1586
|
if request.ssl? || hub_bypass_ssl?
|
1455
1587
|
return true
|
1456
1588
|
else
|
1457
|
-
|
1458
|
-
redirect_to( hubssolib_promote_uri_to_ssl( request.request_uri, request.host ) )
|
1589
|
+
redirect_to(hubssolib_promote_uri_to_ssl(request.original_url))
|
1459
1590
|
return false
|
1460
1591
|
end
|
1461
1592
|
end
|
@@ -1465,21 +1596,32 @@ module HubSsoLib
|
|
1465
1596
|
# dropped. However, we also want this to work without being logged in, so
|
1466
1597
|
# in that case it uses the normal flash as a backup when *writing*.
|
1467
1598
|
#
|
1599
|
+
# This method returns the Hub flash if logged in, else +nil+.
|
1600
|
+
#
|
1468
1601
|
def hubssolib_get_flash
|
1469
1602
|
session = self.hubssolib_get_session()
|
1470
|
-
session&.session_flash
|
1603
|
+
session&.session_flash
|
1471
1604
|
end
|
1472
1605
|
|
1606
|
+
# Set Flash information under the given symbol with the given text message,
|
1607
|
+
# using the Hub cross-application flash store if logged in, else the
|
1608
|
+
# this-application local session flash store otherwise.
|
1609
|
+
#
|
1473
1610
|
def hubssolib_set_flash(symbol, message)
|
1474
1611
|
session = self.hubssolib_get_session()
|
1475
|
-
|
1476
|
-
f
|
1612
|
+
|
1613
|
+
f = hubssolib_get_flash()
|
1614
|
+
f ||= self.flash if self.respond_to?(:flash)
|
1615
|
+
f ||= {}
|
1477
1616
|
|
1478
1617
|
f[symbol] = message
|
1479
1618
|
|
1480
1619
|
session.session_flash = f unless session.nil?
|
1481
1620
|
end
|
1482
1621
|
|
1622
|
+
# Clears the *hub* flash for logged-in users, but not the local application
|
1623
|
+
# session flash.
|
1624
|
+
#
|
1483
1625
|
def hubssolib_clear_flash
|
1484
1626
|
session = self.hubssolib_get_session()
|
1485
1627
|
session.session_flash = {} unless session.nil?
|
@@ -1495,6 +1637,10 @@ module HubSsoLib
|
|
1495
1637
|
# values. This allows both the Hub and standard flashes to have values
|
1496
1638
|
# inside them under the same key. All keys are strings.
|
1497
1639
|
#
|
1640
|
+
# You may well prefer to use #hubssolib_flash_markup to obtain something
|
1641
|
+
# that can be written straight into a view, unless it doesn't meet your
|
1642
|
+
# markup requirements.
|
1643
|
+
#
|
1498
1644
|
def hubssolib_flash_data
|
1499
1645
|
|
1500
1646
|
# These known key values are used to guarantee an order in the output
|
@@ -1510,14 +1656,14 @@ module HubSsoLib
|
|
1510
1656
|
# Get an array of keys for the Hub flash with the ordered key items
|
1511
1657
|
# first and store data from that flash; same again for standard.
|
1512
1658
|
|
1513
|
-
hash = hubssolib_get_flash()
|
1659
|
+
hash = hubssolib_get_flash() || {}
|
1514
1660
|
keys = ordered_keys | hash.keys
|
1515
1661
|
|
1516
1662
|
keys.each do | key |
|
1517
1663
|
compiled_data['hub'][key] = hash[key] if hash.key?(key)
|
1518
1664
|
end
|
1519
1665
|
|
1520
|
-
if
|
1666
|
+
if self.respond_to?( :flash )
|
1521
1667
|
hash = flash.to_h()
|
1522
1668
|
keys = ordered_keys | hash.keys
|
1523
1669
|
|
@@ -1527,11 +1673,60 @@ module HubSsoLib
|
|
1527
1673
|
end
|
1528
1674
|
|
1529
1675
|
hubssolib_clear_flash()
|
1530
|
-
flash.
|
1676
|
+
flash.clear()
|
1531
1677
|
|
1532
1678
|
return compiled_data
|
1533
1679
|
end
|
1534
1680
|
|
1681
|
+
# A companion to #hubssolib_flash_data which returns standardised Flash
|
1682
|
+
# markup for your view. THIS MUST ONLY BE USED IN A VIEW / HELPER, or at
|
1683
|
+
# least somewhere that ActionView::Helpers::TagHelper#tag is available.
|
1684
|
+
#
|
1685
|
+
# * An outer DIV with class "flash" wraps the content.
|
1686
|
+
#
|
1687
|
+
# * Within that, +H2+ tags wrap each message in the flash data. These
|
1688
|
+
# tags also have class "flash", along with an additional tag which is
|
1689
|
+
# equal to the key under which the message was found - so if adding a
|
1690
|
+
# flash message under, say, <tt>:alert</tt>, the rendered result would
|
1691
|
+
# be <tt><h2 class="flash alert">...</h2></tt>.
|
1692
|
+
#
|
1693
|
+
# * As a special case, a key with the suffix <tt>_html_safe</tt> is taken
|
1694
|
+
# to contain HTML-safe strings and potential markup, so you could do
|
1695
|
+
# things like add emphasis, other classes or styles to the data written
|
1696
|
+
# inside the +H2+ tag. Be very careful to make sure any non-markup data
|
1697
|
+
# is properly escaped first. The key-related class in the arising +H2+
|
1698
|
+
# tag _excludes_ the suffix, so e.g. <tt>:notice_html_safe</tt> will
|
1699
|
+
# lead to class +notice+.
|
1700
|
+
#
|
1701
|
+
# Hub session-sourced and Rails local app session-sourced flash data is
|
1702
|
+
# treated the same, with Hub-sourced data listed first. The other is
|
1703
|
+
# otherwise undefined (it's rare for there to be more than one thing in
|
1704
|
+
# the flash at any given time, though).
|
1705
|
+
#
|
1706
|
+
def hubssolib_flash_markup
|
1707
|
+
data = hubssolib_flash_data()
|
1708
|
+
proc = Proc.new do | key, value |
|
1709
|
+
key = key.to_s
|
1710
|
+
|
1711
|
+
if key.end_with?( '_html_safe' )
|
1712
|
+
value = value.html_safe()
|
1713
|
+
key = key.chomp( '_html_safe' )
|
1714
|
+
end
|
1715
|
+
|
1716
|
+
helpers.tag.h2(value, class: "flash #{ key }")
|
1717
|
+
end
|
1718
|
+
|
1719
|
+
return helpers.tag.div(class: 'flash') do
|
1720
|
+
data['hub'].each do | key, value |
|
1721
|
+
helpers.concat(proc.call(key, value))
|
1722
|
+
end
|
1723
|
+
|
1724
|
+
data['standard'].each do | key, value |
|
1725
|
+
helpers.concat(proc.call(key, value))
|
1726
|
+
end
|
1727
|
+
end
|
1728
|
+
end
|
1729
|
+
|
1535
1730
|
# Retrieve the message of an exception stored as an object in the given
|
1536
1731
|
# string.
|
1537
1732
|
#
|
@@ -1548,8 +1743,10 @@ module HubSsoLib
|
|
1548
1743
|
|
1549
1744
|
:hubssolib_current_user,
|
1550
1745
|
:hubssolib_unique_name,
|
1746
|
+
:hubssolib_returnable_account_url,
|
1551
1747
|
:hubssolib_account_link,
|
1552
1748
|
:hubssolib_flash_data,
|
1749
|
+
:hubssolib_flash_markup,
|
1553
1750
|
|
1554
1751
|
:hubssolib_logged_in?,
|
1555
1752
|
:hubssolib_authorized?,
|
@@ -1703,7 +1900,7 @@ module HubSsoLib
|
|
1703
1900
|
#
|
1704
1901
|
if hubssolib_ensure_https
|
1705
1902
|
hubssolib_set_flash(:alert, 'You must log in before you can continue.')
|
1706
|
-
redirect_to
|
1903
|
+
redirect_to hubssolib_returnable_account_url(logged_in: false)
|
1707
1904
|
end
|
1708
1905
|
|
1709
1906
|
return false
|
@@ -1795,16 +1992,6 @@ module HubSsoLib
|
|
1795
1992
|
session = self.hubssolib_get_session()
|
1796
1993
|
session.session_last_used = time unless session.nil?
|
1797
1994
|
end
|
1798
|
-
|
1799
|
-
def hubssolib_get_return_to
|
1800
|
-
self.hubssolib_get_session()&.session_return_to
|
1801
|
-
end
|
1802
|
-
|
1803
|
-
def hubssolib_set_return_to(uri)
|
1804
|
-
session = self.hubssolib_get_session()
|
1805
|
-
session.session_return_to = uri unless session.nil?
|
1806
|
-
end
|
1807
|
-
|
1808
1995
|
end # Core module
|
1809
1996
|
end # HubSsoLib module
|
1810
1997
|
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hubssolib
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.
|
4
|
+
version: 3.8.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andrew Hodgkinson and others
|
8
8
|
bindir: bin
|
9
9
|
cert_chain: []
|
10
|
-
date: 2025-
|
10
|
+
date: 2025-04-09 00:00:00.000000000 Z
|
11
11
|
dependencies:
|
12
12
|
- !ruby/object:Gem::Dependency
|
13
13
|
name: drb
|
@@ -51,6 +51,20 @@ dependencies:
|
|
51
51
|
- - "~>"
|
52
52
|
- !ruby/object:Gem::Version
|
53
53
|
version: '1.1'
|
54
|
+
- !ruby/object:Gem::Dependency
|
55
|
+
name: rails
|
56
|
+
requirement: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - "~>"
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '8.0'
|
61
|
+
type: :development
|
62
|
+
prerelease: false
|
63
|
+
version_requirements: !ruby/object:Gem::Requirement
|
64
|
+
requirements:
|
65
|
+
- - "~>"
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: '8.0'
|
54
68
|
- !ruby/object:Gem::Dependency
|
55
69
|
name: simplecov
|
56
70
|
requirement: !ruby/object:Gem::Requirement
|
@@ -124,6 +138,7 @@ files:
|
|
124
138
|
- Gemfile
|
125
139
|
- Gemfile.lock
|
126
140
|
- README.md
|
141
|
+
- hubssolib-3.7.0.gem
|
127
142
|
- hubssolib.gemspec
|
128
143
|
- lib/hub_sso_lib.rb
|
129
144
|
homepage: http://pond.org.uk/
|