gds-sso 15.0.0 → 16.0.2

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.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +23 -56
  3. data/Rakefile +11 -6
  4. data/app/controllers/api/user_controller.rb +30 -28
  5. data/app/controllers/authentications_controller.rb +4 -6
  6. data/config/routes.rb +7 -6
  7. data/lib/gds-sso.rb +29 -24
  8. data/lib/gds-sso/api_access.rb +1 -1
  9. data/lib/gds-sso/bearer_token.rb +24 -24
  10. data/lib/gds-sso/config.rb +13 -12
  11. data/lib/gds-sso/controller_methods.rb +7 -8
  12. data/lib/gds-sso/failure_app.rb +8 -8
  13. data/lib/gds-sso/lint/user_spec.rb +24 -25
  14. data/lib/gds-sso/lint/user_test.rb +28 -28
  15. data/lib/gds-sso/railtie.rb +12 -0
  16. data/lib/gds-sso/user.rb +12 -12
  17. data/lib/gds-sso/version.rb +1 -1
  18. data/lib/gds-sso/warden_config.rb +21 -31
  19. data/spec/controller/api_user_controller_spec.rb +40 -37
  20. data/spec/controller/controller_methods_spec.rb +28 -42
  21. data/spec/internal/app/controllers/application_controller.rb +1 -1
  22. data/spec/internal/app/controllers/example_controller.rb +1 -2
  23. data/spec/internal/config/initializers/gds-sso.rb +2 -2
  24. data/spec/internal/config/routes.rb +2 -2
  25. data/spec/internal/db/combustion_test.sqlite +0 -0
  26. data/spec/internal/db/schema.rb +5 -5
  27. data/spec/internal/log/test.log +1131 -1123
  28. data/spec/requests/end_to_end_spec.rb +44 -45
  29. data/spec/spec_helper.rb +12 -13
  30. data/spec/support/controller_spy.rb +14 -0
  31. data/spec/support/serializable_user.rb +3 -0
  32. data/spec/support/signon_integration_helpers.rb +10 -8
  33. data/spec/support/test_user.rb +29 -0
  34. data/spec/support/timecop.rb +1 -1
  35. data/spec/unit/api_access_spec.rb +7 -7
  36. data/spec/unit/bearer_token_spec.rb +14 -15
  37. data/spec/unit/config_spec.rb +5 -5
  38. data/spec/unit/mock_bearer_token_spec.rb +4 -4
  39. data/spec/unit/railtie_spec.rb +14 -0
  40. data/spec/unit/session_serialisation_spec.rb +5 -9
  41. data/spec/unit/user_spec.rb +20 -51
  42. metadata +104 -61
@@ -6,20 +6,19 @@ module GDS
6
6
 
7
7
  def self.included(base)
8
8
  base.rescue_from PermissionDeniedException do |e|
9
- if GDS::SSO::Config.api_only?
9
+ if GDS::SSO::Config.api_only
10
10
  render json: { message: e.message }, status: :forbidden
11
11
  else
12
12
  render "authorisations/unauthorised", layout: "unauthorised", status: :forbidden, locals: { message: e.message }
13
13
  end
14
14
  end
15
15
 
16
- unless GDS::SSO::Config.api_only?
16
+ unless GDS::SSO::Config.api_only
17
17
  base.helper_method :user_signed_in?
18
18
  base.helper_method :current_user
19
19
  end
20
20
  end
21
21
 
22
-
23
22
  def authorise_user!(permissions)
24
23
  # Ensure that we're authenticated (and by extension that current_user is set).
25
24
  # Otherwise current_user might be nil, and we'd error out
@@ -52,7 +51,7 @@ module GDS
52
51
  end
53
52
 
54
53
  def user_signed_in?
55
- warden && warden.authenticated? && ! warden.user.remotely_signed_out?
54
+ warden && warden.authenticated? && !warden.user.remotely_signed_out?
56
55
  end
57
56
 
58
57
  def current_user
@@ -64,22 +63,22 @@ module GDS
64
63
  end
65
64
 
66
65
  def warden
67
- request.env['warden']
66
+ request.env["warden"]
68
67
  end
69
68
 
70
- private
69
+ private
71
70
 
72
71
  def authorise_user_with_at_least_one_of_permissions!(permissions)
73
72
  if permissions.none? { |permission| current_user.has_permission?(permission) }
74
73
  raise PermissionDeniedException,
75
- "Sorry, you don't seem to have any of the permissions: #{permissions.to_sentence} for this app."
74
+ "Sorry, you don't seem to have any of the permissions: #{permissions.to_sentence} for this app."
76
75
  end
77
76
  end
78
77
 
79
78
  def authorise_user_with_all_permissions!(permissions)
80
79
  unless permissions.all? { |permission| current_user.has_permission?(permission) }
81
80
  raise PermissionDeniedException,
82
- "Sorry, you don't seem to have all of the permissions: #{permissions.to_sentence} for this app."
81
+ "Sorry, you don't seem to have all of the permissions: #{permissions.to_sentence} for this app."
83
82
  end
84
83
  end
85
84
  end
@@ -1,5 +1,5 @@
1
1
  require "action_controller/metal"
2
- require 'rails'
2
+ require "rails"
3
3
 
4
4
  # Failure application that will be called every time :warden is thrown from
5
5
  # any strategy or hook.
@@ -18,7 +18,7 @@ module GDS
18
18
  def self.call(env)
19
19
  if GDS::SSO::ApiAccess.api_call?(env)
20
20
  action(:api_invalid_token).call(env)
21
- elsif GDS::SSO::Config.api_only?
21
+ elsif GDS::SSO::Config.api_only
22
22
  action(:api_missing_token).call(env)
23
23
  else
24
24
  action(:redirect).call(env)
@@ -27,15 +27,15 @@ module GDS
27
27
 
28
28
  def redirect
29
29
  store_location!
30
- redirect_to '/auth/gds'
30
+ redirect_to "/auth/gds"
31
31
  end
32
32
 
33
33
  def api_invalid_token
34
- api_unauthorized('Bearer token does not appear to be valid', 'invalid_token')
34
+ api_unauthorized("Bearer token does not appear to be valid", "invalid_token")
35
35
  end
36
36
 
37
37
  def api_missing_token
38
- api_unauthorized('No bearer token was provided', 'invalid_request')
38
+ api_unauthorized("No bearer token was provided", "invalid_request")
39
39
  end
40
40
 
41
41
  # Stores requested uri to redirect the user after signing in. We cannot use
@@ -45,13 +45,13 @@ module GDS
45
45
 
46
46
  # TOTALLY NOT DOING THE SCOPE THING. PROBABLY SHOULD.
47
47
  def store_location!
48
- session["return_to"] = request.env['warden.options'][:attempted_path] if request.get?
48
+ session["return_to"] = request.env["warden.options"][:attempted_path] if request.get?
49
49
  end
50
50
 
51
- private
51
+ private
52
52
 
53
53
  def api_unauthorized(message, bearer_error)
54
- headers['WWW-Authenticate'] = %(Bearer error="#{bearer_error}")
54
+ headers["WWW-Authenticate"] = %(Bearer error="#{bearer_error}")
55
55
  render json: { message: message }, status: :unauthorized
56
56
  end
57
57
  end
@@ -1,10 +1,10 @@
1
1
  RSpec.shared_examples "a gds-sso user class" do
2
- subject { described_class.new(:uid => '12345') }
2
+ subject { described_class.new(uid: "12345") }
3
3
 
4
4
  it "implements #where" do
5
5
  expect(described_class).to respond_to(:where)
6
6
 
7
- result = described_class.where(uid: '123')
7
+ result = described_class.where(uid: "123")
8
8
  expect(result).to respond_to(:first)
9
9
  end
10
10
 
@@ -31,49 +31,48 @@ RSpec.shared_examples "a gds-sso user class" do
31
31
  describe "#has_all_permissions?" do
32
32
  it "is false when there are no permissions" do
33
33
  subject.update!(permissions: nil)
34
- required_permissions = ["signin"]
34
+ required_permissions = %w[signin]
35
35
  expect(subject.has_all_permissions?(required_permissions)).to be_falsy
36
36
  end
37
37
 
38
38
  it "is false when it does not have all required permissions" do
39
- subject.update!(permissions: ["signin"])
40
- required_permissions = ["signin", "not_granted_permission_one", "not_granted_permission_two"]
39
+ subject.update!(permissions: %w[signin])
40
+ required_permissions = %w[signin not_granted_permission_one not_granted_permission_two]
41
41
  expect(subject.has_all_permissions?(required_permissions)).to be false
42
42
  end
43
43
 
44
44
  it "is true when it has all required permissions" do
45
- subject.update!(permissions: ["signin", "internal_app"])
46
- required_permissions = ["signin", "internal_app"]
45
+ subject.update!(permissions: %w[signin internal_app])
46
+ required_permissions = %w[signin internal_app]
47
47
  expect(subject.has_all_permissions?(required_permissions)).to be true
48
48
  end
49
-
50
49
  end
51
50
 
52
51
  specify "the User class and GDS::SSO::User mixin work together" do
53
52
  auth_hash = {
54
- 'uid' => '12345',
55
- 'info' => {
56
- 'name' => 'Joe Smith',
57
- 'email' => 'joe.smith@example.com',
53
+ "uid" => "12345",
54
+ "info" => {
55
+ "name" => "Joe Smith",
56
+ "email" => "joe.smith@example.com",
57
+ },
58
+ "extra" => {
59
+ "user" => {
60
+ "disabled" => false,
61
+ "permissions" => %w[signin],
62
+ "organisation_slug" => "cabinet-office",
63
+ "organisation_content_id" => "91e57ad9-29a3-4f94-9ab4-5e9ae6d13588",
64
+ },
58
65
  },
59
- 'extra' => {
60
- 'user' => {
61
- 'disabled' => false,
62
- 'permissions' => ['signin'],
63
- 'organisation_slug' => 'cabinet-office',
64
- 'organisation_content_id' => '91e57ad9-29a3-4f94-9ab4-5e9ae6d13588'
65
- }
66
- }
67
66
  }
68
67
 
69
68
  user = described_class.find_for_gds_oauth(auth_hash)
70
69
  expect(user).to be_an_instance_of(described_class)
71
- expect(user.uid).to eq('12345')
70
+ expect(user.uid).to eq("12345")
72
71
  expect(user.name).to eq("Joe Smith")
73
- expect(user.email).to eq('joe.smith@example.com')
72
+ expect(user.email).to eq("joe.smith@example.com")
74
73
  expect(user).not_to be_disabled
75
- expect(user.permissions).to eq(['signin'])
76
- expect(user.organisation_slug).to eq('cabinet-office')
77
- expect(user.organisation_content_id).to eq('91e57ad9-29a3-4f94-9ab4-5e9ae6d13588')
74
+ expect(user.permissions).to eq(%w[signin])
75
+ expect(user.organisation_slug).to eq("cabinet-office")
76
+ expect(user.organisation_content_id).to eq("91e57ad9-29a3-4f94-9ab4-5e9ae6d13588")
78
77
  end
79
78
  end
@@ -17,58 +17,58 @@ module GDS
17
17
  #
18
18
  class UserTest < ActiveSupport::TestCase
19
19
  def user_class
20
- raise 'Reopen `GDS::SSO::Lint::UserTest` and add `#user_class` to return the class including `GDS::SSO::User`'
20
+ raise "Reopen `GDS::SSO::Lint::UserTest` and add `#user_class` to return the class including `GDS::SSO::User`"
21
21
  end
22
22
 
23
23
  setup do
24
- @lint_user = user_class.new(uid: '12345')
24
+ @lint_user = user_class.new(uid: "12345")
25
25
  end
26
26
 
27
- test 'implement #where' do
28
- result = user_class.where(uid: '123')
27
+ test "implement #where" do
28
+ result = user_class.where(uid: "123")
29
29
  assert result.respond_to?(:first)
30
30
  end
31
31
 
32
- test 'implement #update_attribute' do
32
+ test "implement #update_attribute" do
33
33
  @lint_user.update_attribute(:remotely_signed_out, true)
34
34
  assert @lint_user.remotely_signed_out?
35
35
  end
36
36
 
37
- test 'implement #update!' do
38
- @lint_user.update!(email: 'test@example.com')
39
- assert_equal @lint_user.email, 'test@example.com'
37
+ test "implement #update!" do
38
+ @lint_user.update!(email: "test@example.com")
39
+ assert_equal @lint_user.email, "test@example.com"
40
40
  end
41
41
 
42
- test 'implement #create!' do
42
+ test "implement #create!" do
43
43
  assert user_class.respond_to?(:create!)
44
44
  end
45
45
 
46
- test 'verify the User class and GDS::SSO::User work together' do
46
+ test "verify the User class and GDS::SSO::User work together" do
47
47
  auth_hash = {
48
- 'uid' => '12345',
49
- 'info' => {
50
- 'name' => 'Joe Smith',
51
- 'email' => 'joe.smith@example.com',
48
+ "uid" => "12345",
49
+ "info" => {
50
+ "name" => "Joe Smith",
51
+ "email" => "joe.smith@example.com",
52
+ },
53
+ "extra" => {
54
+ "user" => {
55
+ "disabled" => false,
56
+ "permissions" => %w[signin],
57
+ "organisation_slug" => "cabinet-office",
58
+ "organisation_content_id" => "91e57ad9-29a3-4f94-9ab4-5e9ae6d13588",
59
+ },
52
60
  },
53
- 'extra' => {
54
- 'user' => {
55
- 'disabled' => false,
56
- 'permissions' => ['signin'],
57
- 'organisation_slug' => 'cabinet-office',
58
- 'organisation_content_id' => '91e57ad9-29a3-4f94-9ab4-5e9ae6d13588',
59
- }
60
- }
61
61
  }
62
62
 
63
63
  user = user_class.find_for_gds_oauth(auth_hash)
64
64
  assert_equal user_class, user.class
65
- assert_equal '12345', user.uid
66
- assert_equal 'Joe Smith', user.name
67
- assert_equal 'joe.smith@example.com', user.email
65
+ assert_equal "12345", user.uid
66
+ assert_equal "Joe Smith", user.name
67
+ assert_equal "joe.smith@example.com", user.email
68
68
  assert_equal false, user.disabled
69
- assert_equal ['signin'], user.permissions
70
- assert_equal 'cabinet-office', user.organisation_slug
71
- assert_equal '91e57ad9-29a3-4f94-9ab4-5e9ae6d13588', user.organisation_content_id
69
+ assert_equal %w[signin], user.permissions
70
+ assert_equal "cabinet-office", user.organisation_slug
71
+ assert_equal "91e57ad9-29a3-4f94-9ab4-5e9ae6d13588", user.organisation_content_id
72
72
  end
73
73
  end
74
74
  end
@@ -0,0 +1,12 @@
1
+ module GDS
2
+ module SSO
3
+ class Railtie < Rails::Railtie
4
+ initializer "gds-sso.initializer" do
5
+ GDS::SSO.config do |config|
6
+ config.cache = Rails.cache
7
+ config.api_only = Rails.configuration.api_only
8
+ end
9
+ end
10
+ end
11
+ end
12
+ end
data/lib/gds-sso/user.rb CHANGED
@@ -1,4 +1,4 @@
1
- require 'active_support/concern'
1
+ require "active_support/concern"
2
2
 
3
3
  module GDS
4
4
  module SSO
@@ -21,29 +21,29 @@ module GDS
21
21
 
22
22
  def self.user_params_from_auth_hash(auth_hash)
23
23
  {
24
- 'uid' => auth_hash['uid'],
25
- 'email' => auth_hash['info']['email'],
26
- 'name' => auth_hash['info']['name'],
27
- 'permissions' => auth_hash['extra']['user']['permissions'],
28
- 'organisation_slug' => auth_hash['extra']['user']['organisation_slug'],
29
- 'organisation_content_id' => auth_hash['extra']['user']['organisation_content_id'],
30
- 'disabled' => auth_hash['extra']['user']['disabled'],
24
+ "uid" => auth_hash["uid"],
25
+ "email" => auth_hash["info"]["email"],
26
+ "name" => auth_hash["info"]["name"],
27
+ "permissions" => auth_hash["extra"]["user"]["permissions"],
28
+ "organisation_slug" => auth_hash["extra"]["user"]["organisation_slug"],
29
+ "organisation_content_id" => auth_hash["extra"]["user"]["organisation_content_id"],
30
+ "disabled" => auth_hash["extra"]["user"]["disabled"],
31
31
  }
32
32
  end
33
33
 
34
34
  def clear_remotely_signed_out!
35
- self.update_attribute(:remotely_signed_out, false)
35
+ update_attribute(:remotely_signed_out, false)
36
36
  end
37
37
 
38
38
  def set_remotely_signed_out!
39
- self.update_attribute(:remotely_signed_out, true)
39
+ update_attribute(:remotely_signed_out, true)
40
40
  end
41
41
 
42
42
  module ClassMethods
43
43
  def find_for_gds_oauth(auth_hash)
44
44
  user_params = GDS::SSO::User.user_params_from_auth_hash(auth_hash.to_hash)
45
- user = self.where(:uid => user_params['uid']).first ||
46
- self.where(:email => user_params['email']).first
45
+ user = where(uid: user_params["uid"]).first ||
46
+ where(email: user_params["email"]).first
47
47
 
48
48
  if user
49
49
  user.update!(user_params)
@@ -1,5 +1,5 @@
1
1
  module GDS
2
2
  module SSO
3
- VERSION = "15.0.0"
3
+ VERSION = "16.0.2".freeze
4
4
  end
5
5
  end
@@ -1,63 +1,55 @@
1
- require 'warden'
2
- require 'warden-oauth2'
3
- require 'gds-sso/bearer_token'
1
+ require "warden"
2
+ require "warden-oauth2"
3
+ require "gds-sso/bearer_token"
4
4
 
5
5
  def logger
6
- if Rails.logger # if we are actually running in a rails app
7
- Rails.logger
8
- else
9
- env['rack.logger']
10
- end
6
+ Rails.logger || env["rack.logger"]
11
7
  end
12
8
 
13
- Warden::Manager.after_authentication do |user, auth, opts|
9
+ Warden::Manager.after_authentication do |user, _auth, _opts|
14
10
  # We've successfully signed in.
15
11
  # If they were remotely signed out, clear the flag as they're no longer suspended
16
12
  user.clear_remotely_signed_out!
17
13
  end
18
14
 
19
15
  Warden::Manager.serialize_into_session do |user|
20
- if user.respond_to?(:uid) and user.uid
16
+ if user.respond_to?(:uid) && user.uid
21
17
  [user.uid, Time.now.utc.iso8601]
22
- else
23
- nil
24
18
  end
25
19
  end
26
20
 
27
21
  Warden::Manager.serialize_from_session do |(uid, auth_timestamp)|
28
22
  # This will reject old sessions that don't have a previous login timestamp
29
23
  if auth_timestamp.is_a?(String)
30
- auth_timestamp = begin
31
- Time.parse(auth_timestamp)
24
+ begin
25
+ auth_timestamp = Time.parse(auth_timestamp)
32
26
  rescue ArgumentError
33
- nil
27
+ auth_timestamp = nil
34
28
  end
35
29
  end
36
30
 
37
- if auth_timestamp and (auth_timestamp + GDS::SSO::Config.auth_valid_for) > Time.now.utc
38
- GDS::SSO::Config.user_klass.where(:uid => uid, :remotely_signed_out => false).first
39
- else
40
- nil
31
+ if auth_timestamp && ((auth_timestamp + GDS::SSO::Config.auth_valid_for) > Time.now.utc)
32
+ GDS::SSO::Config.user_klass.where(uid: uid, remotely_signed_out: false).first
41
33
  end
42
34
  end
43
35
 
44
36
  Warden::Strategies.add(:gds_sso) do
45
37
  def valid?
46
- ! ::GDS::SSO::ApiAccess.api_call?(env)
38
+ !::GDS::SSO::ApiAccess.api_call?(env)
47
39
  end
48
40
 
49
41
  def authenticate!
50
42
  logger.debug("Authenticating with gds_sso strategy")
51
43
 
52
- if request.env['omniauth.auth'].nil?
44
+ if request.env["omniauth.auth"].nil?
53
45
  fail!("No credentials, bub")
54
46
  else
55
- user = prep_user(request.env['omniauth.auth'])
47
+ user = prep_user(request.env["omniauth.auth"])
56
48
  success!(user)
57
49
  end
58
50
  end
59
51
 
60
- private
52
+ private
61
53
 
62
54
  def prep_user(auth_hash)
63
55
  user = GDS::SSO::Config.user_klass.find_for_gds_oauth(auth_hash)
@@ -73,27 +65,25 @@ Warden::Strategies.add(:gds_bearer_token, Warden::OAuth2::Strategies::Bearer)
73
65
 
74
66
  Warden::Strategies.add(:mock_gds_sso) do
75
67
  def valid?
76
- ! ::GDS::SSO::ApiAccess.api_call?(env)
68
+ !::GDS::SSO::ApiAccess.api_call?(env)
77
69
  end
78
70
 
79
71
  def authenticate!
80
72
  logger.warn("Authenticating with mock_gds_sso strategy")
81
73
 
82
74
  test_user = GDS::SSO.test_user
83
- test_user ||= ENV['GDS_SSO_MOCK_INVALID'].present? ? nil : GDS::SSO::Config.user_klass.first
75
+ test_user ||= ENV["GDS_SSO_MOCK_INVALID"].present? ? nil : GDS::SSO::Config.user_klass.first
84
76
  if test_user
85
77
  # Brute force ensure test user has correct perms to signin
86
- if ! test_user.has_permission?("signin")
78
+ unless test_user.has_permission?("signin")
87
79
  permissions = test_user.permissions || []
88
80
  test_user.update_attribute(:permissions, permissions << "signin")
89
81
  end
90
82
  success!(test_user)
83
+ elsif Rails.env.test? && ENV["GDS_SSO_MOCK_INVALID"].present?
84
+ fail!(:invalid)
91
85
  else
92
- if Rails.env.test? && ENV['GDS_SSO_MOCK_INVALID'].present?
93
- fail!(:invalid)
94
- else
95
- raise "GDS-SSO running in mock mode and no test user found. Normally we'd load the first user in the database. Create a user in the database."
96
- end
86
+ raise "GDS-SSO running in mock mode and no test user found. Normally we'd load the first user in the database. Create a user in the database."
97
87
  end
98
88
  end
99
89
  end