g5_authenticatable 1.1.2.rc.5 → 1.1.2

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: 8d8204cfd1ee04db6688383643abe78fa173d66249c095c3ca821b6678f507ae
4
- data.tar.gz: cce2bfe1e6405025b1ebb7b3ba5d9ec9cd7cb747097799a26973918d9a29cc3c
3
+ metadata.gz: ca74934a2271fb30c2157b5bbeb73e42cf11e889590cd7d6997838b54ca338a4
4
+ data.tar.gz: 88ddc54dab96e37fb8eba1b91e2c592e02702ea58608e1637e650423fdc1ffeb
5
5
  SHA512:
6
- metadata.gz: 89c147791e2c162461c094e20d6f701dbbee03a83679710a242329ea0d0f456a34449697967eb3d7a4bc949a8c15b768bf084850cd349eb06cafc774213978ce
7
- data.tar.gz: 666e996ac402ad549affa4d8a9e23df4c852a0cf38c6e453c14810e802106522fec637a8e8f087d5e7702641b09aab8aca1eda18e0d9dad91ab5632caeadedf6
6
+ metadata.gz: f1441a6616b5391c160d11bb5cd50d5eba4ade947b645d4c50d5c4ccf9b5190a5bf764ae554daa9403bdbfe98e9d9b573a757e5b5c013f0c8a0b8ce5f61428d9
7
+ data.tar.gz: 85dda61de7dd6dbfb7eabee427d7fd0f9883cfd01ac37662f632b0130039ee6c8b346d49b9e88783be8d48863b4b5f10a1bff7de15df24b74dbef7ccf378c71c
data/CHANGELOG.md CHANGED
@@ -1,3 +1,5 @@
1
+ ## v1.1.2 (2018-12-20)
2
+ * Adding `User.current_client_urn` to better support Pundit authorization
1
3
  ## v1.1.1 (2018-06-21)
2
4
 
3
5
  * Support rails 5.2 green field apps, including fixes for setting the default
data/README.md CHANGED
@@ -76,7 +76,7 @@ root to: 'home#index'
76
76
  ### Registering your OAuth application
77
77
 
78
78
  1. Visit the auth server admin console and login:
79
- * For development, visit https://dev-auth.g5search.com/admin
79
+ * For development, visit https://auth-staging.g5devops.com/admin
80
80
  * For production, visit https://auth.g5search.com/admin
81
81
  2. Click "New Application"
82
82
  3. Enter a name that recognizably identifies your application.
@@ -106,7 +106,7 @@ environment variables for your client application:
106
106
  * `G5_AUTH_CLIENT_SECRET` - the OAuth 2.0 application secret from the auth server
107
107
  * `G5_AUTH_REDIRECT_URI` - the OAuth 2.0 redirect URI registered with the auth server
108
108
  * `G5_AUTH_ENDPOINT` - the endpoint URL (without any path info) for the G5 auth server.
109
- Generally, this will be set to either `https://dev-auth.g5search.com` or
109
+ Generally, this will be set to either `https://auth-staging.g5devops.com` or
110
110
  `https://auth.g5search.com` (the default).
111
111
 
112
112
  If you need to make server-to-server API calls that are not associated with an
@@ -9,6 +9,7 @@ module G5Authenticatable
9
9
 
10
10
  validates :email, presence: true, uniqueness: true
11
11
  validates_uniqueness_of :uid, scope: :provider
12
+ attr_accessor :current_client_urn # helpful for authorizing in Pudit
12
13
 
13
14
  GLOBAL_ROLE = 'GLOBAL'
14
15
 
@@ -92,7 +92,7 @@ module G5Authenticatable
92
92
  end
93
93
 
94
94
  def global_role?
95
- user.roles.global.exists?
95
+ super_admin? || admin? || editor? || viewer?
96
96
  end
97
97
  end
98
98
  end
@@ -2,6 +2,8 @@
2
2
  <html>
3
3
  <head>
4
4
  <title>G5Authenticatable</title>
5
+ <%= stylesheet_link_tag "g5_authenticatable/application", :media => "all" %>
6
+ <%= javascript_include_tag "g5_authenticatable/application" %>
5
7
  <%= csrf_meta_tags %>
6
8
  </head>
7
9
  <body>
@@ -22,7 +22,7 @@ Gem::Specification.new do |spec|
22
22
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
23
23
  spec.require_paths = ['lib']
24
24
 
25
- spec.add_dependency 'devise_g5_authenticatable', '1.0.1.rc.1'
25
+ spec.add_dependency 'devise_g5_authenticatable', '~> 1.0'
26
26
  spec.add_dependency 'g5_authenticatable_api', '~> 1.0'
27
27
  spec.add_dependency 'rolify', '~> 5.1.0'
28
28
  spec.add_dependency 'pundit', '~> 1.0'
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module G5Authenticatable
4
- VERSION = '1.1.2.rc.5'
4
+ VERSION = '1.1.2'
5
5
  end
@@ -9,6 +9,11 @@ RSpec.describe G5Authenticatable::User do
9
9
 
10
10
  it { is_expected.to have_and_belong_to_many(:roles) }
11
11
 
12
+ it 'has an current_client_urn attr_accessor' do
13
+ subject.current_client_urn = 'foo'
14
+ expect(subject.current_client_urn).to eq('foo')
15
+ end
16
+
12
17
  it 'should expose the email' do
13
18
  expect(user.email).to eq(user_attributes[:email])
14
19
  end
@@ -68,30 +73,30 @@ RSpec.describe G5Authenticatable::User do
68
73
  full_name = [new_user_attributes[:first_name],
69
74
  new_user_attributes[:last_name]].join(' ')
70
75
  OmniAuth::AuthHash.new(
71
- 'uid' => new_user_attributes[:uid],
72
- 'provider' => new_user_attributes[:provider],
73
- 'info' => {
74
- 'email' => new_user_attributes[:email],
75
- 'name' => full_name,
76
- 'first_name' => new_user_attributes[:first_name],
77
- 'last_name' => new_user_attributes[:last_name],
78
- 'phone' => new_user_attributes[:phone_number]
79
- },
80
- 'credentials' => {
81
- 'token' => new_user_attributes[:g5_access_token],
82
- 'expires' => true,
83
- 'expires_at' => Time.now + 1000
84
- },
85
- 'extra' => {
86
- 'title' => new_user_attributes[:title],
87
- 'organization_name' => new_user_attributes[:organization_name],
88
- 'roles' => [
89
- { 'name' => new_role_attributes[:name],
90
- 'type' => 'GLOBAL',
91
- 'urn' => nil }
92
- ],
93
- 'raw_info' => {}
94
- }
76
+ 'uid' => new_user_attributes[:uid],
77
+ 'provider' => new_user_attributes[:provider],
78
+ 'info' => {
79
+ 'email' => new_user_attributes[:email],
80
+ 'name' => full_name,
81
+ 'first_name' => new_user_attributes[:first_name],
82
+ 'last_name' => new_user_attributes[:last_name],
83
+ 'phone' => new_user_attributes[:phone_number]
84
+ },
85
+ 'credentials' => {
86
+ 'token' => new_user_attributes[:g5_access_token],
87
+ 'expires' => true,
88
+ 'expires_at' => Time.now + 1000
89
+ },
90
+ 'extra' => {
91
+ 'title' => new_user_attributes[:title],
92
+ 'organization_name' => new_user_attributes[:organization_name],
93
+ 'roles' => [
94
+ { 'name' => new_role_attributes[:name],
95
+ 'type' => 'GLOBAL',
96
+ 'urn' => nil }
97
+ ],
98
+ 'raw_info' => {}
99
+ }
95
100
  )
96
101
  end
97
102
 
@@ -108,17 +113,17 @@ RSpec.describe G5Authenticatable::User do
108
113
 
109
114
  it 'has the correct provider' do
110
115
  expect(attributes_from_auth[:provider])
111
- .to eq(new_user_attributes[:provider])
116
+ .to eq(new_user_attributes[:provider])
112
117
  end
113
118
 
114
119
  it 'has the correct first_name' do
115
120
  expect(attributes_from_auth[:first_name])
116
- .to eq(new_user_attributes[:first_name])
121
+ .to eq(new_user_attributes[:first_name])
117
122
  end
118
123
 
119
124
  it 'has the correct last_name' do
120
125
  expect(attributes_from_auth[:last_name])
121
- .to eq(new_user_attributes[:last_name])
126
+ .to eq(new_user_attributes[:last_name])
122
127
  end
123
128
 
124
129
  it 'has the correct email' do
@@ -127,7 +132,7 @@ RSpec.describe G5Authenticatable::User do
127
132
 
128
133
  it 'has the correct phone_number' do
129
134
  expect(attributes_from_auth[:phone_number])
130
- .to eq(new_user_attributes[:phone_number])
135
+ .to eq(new_user_attributes[:phone_number])
131
136
  end
132
137
 
133
138
  it 'has the correct title' do
@@ -136,7 +141,7 @@ RSpec.describe G5Authenticatable::User do
136
141
 
137
142
  it 'has the correct organization_name' do
138
143
  expect(attributes_from_auth[:organization_name])
139
- .to eq(new_user_attributes[:organization_name])
144
+ .to eq(new_user_attributes[:organization_name])
140
145
  end
141
146
  end
142
147
 
@@ -150,29 +155,29 @@ RSpec.describe G5Authenticatable::User do
150
155
  full_name = [new_user_attributes[:first_name],
151
156
  new_user_attributes[:last_name]].join(' ')
152
157
  OmniAuth::AuthHash.new(
153
- 'provider' => new_user_attributes[:provider],
154
- 'info' => {
155
- 'email' => new_user_attributes[:email],
156
- 'name' => full_name,
157
- 'first_name' => new_user_attributes[:first_name],
158
- 'last_name' => new_user_attributes[:last_name],
159
- 'phone' => new_user_attributes[:phone_number]
160
- },
161
- 'credentials' => {
162
- 'token' => new_user_attributes[:g5_access_token],
163
- 'expires' => true,
164
- 'expires_at' => Time.now + 1000
165
- },
166
- 'extra' => {
167
- 'title' => new_user_attributes[:title],
168
- 'organization_name' => new_user_attributes[:organization_name],
169
- 'roles' => [
170
- { 'name' => new_role_attributes[:name],
171
- 'type' => 'GLOBAL',
172
- 'urn' => nil }
173
- ],
174
- 'raw_info' => {}
175
- }
158
+ 'provider' => new_user_attributes[:provider],
159
+ 'info' => {
160
+ 'email' => new_user_attributes[:email],
161
+ 'name' => full_name,
162
+ 'first_name' => new_user_attributes[:first_name],
163
+ 'last_name' => new_user_attributes[:last_name],
164
+ 'phone' => new_user_attributes[:phone_number]
165
+ },
166
+ 'credentials' => {
167
+ 'token' => new_user_attributes[:g5_access_token],
168
+ 'expires' => true,
169
+ 'expires_at' => Time.now + 1000
170
+ },
171
+ 'extra' => {
172
+ 'title' => new_user_attributes[:title],
173
+ 'organization_name' => new_user_attributes[:organization_name],
174
+ 'roles' => [
175
+ { 'name' => new_role_attributes[:name],
176
+ 'type' => 'GLOBAL',
177
+ 'urn' => nil }
178
+ ],
179
+ 'raw_info' => {}
180
+ }
176
181
  )
177
182
  end
178
183
 
@@ -237,7 +242,7 @@ RSpec.describe G5Authenticatable::User do
237
242
 
238
243
  it 'should set the organization_name from the session data' do
239
244
  expect(new_user.organization_name)
240
- .to eq(new_user_attributes[:organization_name])
245
+ .to eq(new_user_attributes[:organization_name])
241
246
  end
242
247
 
243
248
  it 'should assign the role from the session data' do
@@ -281,11 +286,11 @@ RSpec.describe G5Authenticatable::User do
281
286
 
282
287
  let(:user_attributes) do
283
288
  FactoryBot.attributes_for(:g5_authenticatable_user,
284
- first_name: nil,
285
- last_name: nil,
286
- phone_number: nil,
287
- title: nil,
288
- organization_name: nil)
289
+ first_name: nil,
290
+ last_name: nil,
291
+ phone_number: nil,
292
+ title: nil,
293
+ organization_name: nil)
289
294
  end
290
295
  let(:role_name) { :my_role }
291
296
 
@@ -296,27 +301,27 @@ RSpec.describe G5Authenticatable::User do
296
301
 
297
302
  let(:auth_data) do
298
303
  OmniAuth::AuthHash.new(
299
- 'provider' => user_attributes[:provider],
300
- 'uid' => user_attributes[:uid],
301
- 'info' => {
302
- 'email' => updated_attributes[:email],
303
- 'first_name' => updated_attributes[:first_name],
304
- 'last_name' => updated_attributes[:last_name],
305
- 'phone' => updated_attributes[:phone_number]
306
- },
307
- 'credentials' => {
308
- 'token' => updated_attributes[:g5_access_token],
309
- 'expires' => true,
310
- 'expires_at' => Time.now + 1000
311
- },
312
- 'extra' => {
313
- 'title' => updated_attributes[:title],
314
- 'organization_name' => updated_attributes[:organization_name],
315
- 'roles' => [
316
- { name: updated_role_name, type: 'GLOBAL', urn: nil }
317
- ],
318
- 'raw_info' => {}
319
- }
304
+ 'provider' => user_attributes[:provider],
305
+ 'uid' => user_attributes[:uid],
306
+ 'info' => {
307
+ 'email' => updated_attributes[:email],
308
+ 'first_name' => updated_attributes[:first_name],
309
+ 'last_name' => updated_attributes[:last_name],
310
+ 'phone' => updated_attributes[:phone_number]
311
+ },
312
+ 'credentials' => {
313
+ 'token' => updated_attributes[:g5_access_token],
314
+ 'expires' => true,
315
+ 'expires_at' => Time.now + 1000
316
+ },
317
+ 'extra' => {
318
+ 'title' => updated_attributes[:title],
319
+ 'organization_name' => updated_attributes[:organization_name],
320
+ 'roles' => [
321
+ { name: updated_role_name, type: 'GLOBAL', urn: nil }
322
+ ],
323
+ 'raw_info' => {}
324
+ }
320
325
  )
321
326
  end
322
327
 
@@ -328,7 +333,7 @@ RSpec.describe G5Authenticatable::User do
328
333
 
329
334
  it 'should update the access token' do
330
335
  expect { updated_user }.to change { user.reload.g5_access_token }
331
- .to(updated_attributes[:g5_access_token])
336
+ .to(updated_attributes[:g5_access_token])
332
337
  end
333
338
 
334
339
  it 'should return the updated user' do
@@ -367,15 +372,15 @@ RSpec.describe G5Authenticatable::User do
367
372
  context 'when user info has changed' do
368
373
  let(:updated_attributes) do
369
374
  {
370
- uid: user.uid,
371
- provider: user.provider,
372
- email: 'updated.email@test.host',
373
- g5_access_token: 'updatedtoken42',
374
- first_name: 'Updated First Name',
375
- last_name: 'Updated Last Name',
376
- phone_number: '555.555.5555 x123',
377
- title: 'Recently Promoted',
378
- organization_name: 'Updated Department'
375
+ uid: user.uid,
376
+ provider: user.provider,
377
+ email: 'updated.email@test.host',
378
+ g5_access_token: 'updatedtoken42',
379
+ first_name: 'Updated First Name',
380
+ last_name: 'Updated Last Name',
381
+ phone_number: '555.555.5555 x123',
382
+ title: 'Recently Promoted',
383
+ organization_name: 'Updated Department'
379
384
  }
380
385
  end
381
386
 
@@ -383,7 +388,7 @@ RSpec.describe G5Authenticatable::User do
383
388
 
384
389
  it 'should update the access token' do
385
390
  expect { updated_user }.to change { user.reload.g5_access_token }
386
- .to(updated_attributes[:g5_access_token])
391
+ .to(updated_attributes[:g5_access_token])
387
392
  end
388
393
 
389
394
  it 'should return the updated user' do
@@ -400,32 +405,32 @@ RSpec.describe G5Authenticatable::User do
400
405
 
401
406
  it 'should update the email' do
402
407
  expect { updated_user }.to change { user.reload.email }
403
- .to(updated_attributes[:email])
408
+ .to(updated_attributes[:email])
404
409
  end
405
410
 
406
411
  it 'should update the first name' do
407
412
  expect { updated_user }.to change { user.reload.first_name }
408
- .to(updated_attributes[:first_name])
413
+ .to(updated_attributes[:first_name])
409
414
  end
410
415
 
411
416
  it 'should update the last name' do
412
417
  expect { updated_user }.to change { user.reload.last_name }
413
- .to(updated_attributes[:last_name])
418
+ .to(updated_attributes[:last_name])
414
419
  end
415
420
 
416
421
  it 'should update the phone number' do
417
422
  expect { updated_user }.to change { user.reload.phone_number }
418
- .to(updated_attributes[:phone_number])
423
+ .to(updated_attributes[:phone_number])
419
424
  end
420
425
 
421
426
  it 'should update the title' do
422
427
  expect { updated_user }.to change { user.reload.title }
423
- .to(updated_attributes[:title])
428
+ .to(updated_attributes[:title])
424
429
  end
425
430
 
426
431
  it 'should update the organization_name' do
427
432
  expect { updated_user }.to change { user.reload.organization_name }
428
- .to(updated_attributes[:organization_name])
433
+ .to(updated_attributes[:organization_name])
429
434
  end
430
435
 
431
436
  it 'should unassign the old role' do
@@ -503,25 +508,25 @@ RSpec.describe G5Authenticatable::User do
503
508
 
504
509
  let(:auth_data) do
505
510
  OmniAuth::AuthHash.new(
506
- 'provider' => user_attributes[:provider],
507
- 'uid' => user_attributes[:uid],
508
- 'info' => {
509
- 'email' => user_attributes[:email],
510
- 'first_name' => user_attributes[:first_name],
511
- 'last_name' => user_attributes[:last_name],
512
- 'phone' => user_attributes[:phone_number]
513
- },
514
- 'credentials' => {
515
- 'token' => user_attributes[:g5_access_token],
516
- 'expires' => true,
517
- 'expires_at' => Time.now + 1000
518
- },
519
- 'extra' => {
520
- 'title' => user_attributes[:title],
521
- 'organization_name' => user_attributes[:organization_name],
522
- 'roles' => roles,
523
- 'raw_info' => {}
524
- }
511
+ 'provider' => user_attributes[:provider],
512
+ 'uid' => user_attributes[:uid],
513
+ 'info' => {
514
+ 'email' => user_attributes[:email],
515
+ 'first_name' => user_attributes[:first_name],
516
+ 'last_name' => user_attributes[:last_name],
517
+ 'phone' => user_attributes[:phone_number]
518
+ },
519
+ 'credentials' => {
520
+ 'token' => user_attributes[:g5_access_token],
521
+ 'expires' => true,
522
+ 'expires_at' => Time.now + 1000
523
+ },
524
+ 'extra' => {
525
+ 'title' => user_attributes[:title],
526
+ 'organization_name' => user_attributes[:organization_name],
527
+ 'roles' => roles,
528
+ 'raw_info' => {}
529
+ }
525
530
  )
526
531
  end
527
532
 
@@ -532,7 +537,7 @@ RSpec.describe G5Authenticatable::User do
532
537
 
533
538
  it 'will add a global role' do
534
539
  expect { user.update_roles_from_auth(auth_data) }
535
- .to change { user.roles.length }.from(0).to(1)
540
+ .to change { user.roles.length }.from(0).to(1)
536
541
  expect(user.roles.first.name).to eq('admin')
537
542
  expect(user.roles.first.resource).to be_nil
538
543
  end
@@ -545,7 +550,7 @@ RSpec.describe G5Authenticatable::User do
545
550
 
546
551
  it 'will add a scoped role' do
547
552
  expect { user.update_roles_from_auth(auth_data) }
548
- .to change { user.roles.length }.from(0).to(1)
553
+ .to change { user.roles.length }.from(0).to(1)
549
554
  expect(user.roles.first.name).to eq('viewer')
550
555
  expect(user.roles.first.resource_id).to eq(resource.id)
551
556
  expect(user.roles.first.resource_type).to eq(resource.class.name)
@@ -555,14 +560,14 @@ RSpec.describe G5Authenticatable::User do
555
560
  context 'with a more than 1 role' do
556
561
  let(:roles) do
557
562
  [
558
- { name: 'viewer', type: resource.class.name, urn: resource.urn },
559
- { name: 'admin', type: 'GLOBAL', urn: nil }
563
+ { name: 'viewer', type: resource.class.name, urn: resource.urn },
564
+ { name: 'admin', type: 'GLOBAL', urn: nil }
560
565
  ]
561
566
  end
562
567
 
563
568
  it 'will add a scoped role' do
564
569
  expect { user.update_roles_from_auth(auth_data) }
565
- .to change { user.roles.length }.from(0).to(2)
570
+ .to change { user.roles.length }.from(0).to(2)
566
571
  end
567
572
  end
568
573
 
@@ -575,7 +580,7 @@ RSpec.describe G5Authenticatable::User do
575
580
 
576
581
  it 'will add a scoped role' do
577
582
  expect { user.update_roles_from_auth(auth_data) }
578
- .to_not change { user.roles.length }
583
+ .to_not change { user.roles.length }
579
584
  end
580
585
  end
581
586
 
@@ -584,21 +589,21 @@ RSpec.describe G5Authenticatable::User do
584
589
 
585
590
  it 'will add a scoped role' do
586
591
  expect { user.update_roles_from_auth(auth_data) }
587
- .to_not change { user.roles.length }.from(0)
592
+ .to_not change { user.roles.length }.from(0)
588
593
  end
589
594
  end
590
595
 
591
596
  context 'with a bad role type' do
592
597
  let(:roles) do
593
598
  [
594
- { name: 'viewer', type: resource.class.name, urn: resource.urn },
595
- { name: 'viewer', type: 'BadResource', urn: resource.urn }
599
+ { name: 'viewer', type: resource.class.name, urn: resource.urn },
600
+ { name: 'viewer', type: 'BadResource', urn: resource.urn }
596
601
  ]
597
602
  end
598
603
 
599
604
  it 'will skip the bad role' do
600
605
  expect { user.update_roles_from_auth(auth_data) }
601
- .to change { user.roles.length }.from(0).to(1)
606
+ .to change { user.roles.length }.from(0).to(1)
602
607
  expect(user.roles.first.name).to eq('viewer')
603
608
  expect(user.roles.first.resource_id).to eq(resource.id)
604
609
  expect(user.roles.first.resource_type).to eq(resource.class.name)
metadata CHANGED
@@ -1,29 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: g5_authenticatable
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.2.rc.5
4
+ version: 1.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - maeve
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-12-06 00:00:00.000000000 Z
11
+ date: 2018-12-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: devise_g5_authenticatable
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - '='
17
+ - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: 1.0.1.rc.1
19
+ version: '1.0'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - '='
24
+ - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: 1.0.1.rc.1
26
+ version: '1.0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: g5_authenticatable_api
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -303,12 +303,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
303
303
  version: '0'
304
304
  required_rubygems_version: !ruby/object:Gem::Requirement
305
305
  requirements:
306
- - - ">"
306
+ - - ">="
307
307
  - !ruby/object:Gem::Version
308
- version: 1.3.1
308
+ version: '0'
309
309
  requirements: []
310
310
  rubyforge_project:
311
- rubygems_version: 2.7.7
311
+ rubygems_version: 2.7.6
312
312
  signing_key:
313
313
  specification_version: 4
314
314
  summary: An authentication engine for G5 applications.