gds-sso 15.0.0 → 15.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (36) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +11 -6
  3. data/app/controllers/api/user_controller.rb +30 -28
  4. data/app/controllers/authentications_controller.rb +3 -5
  5. data/config/routes.rb +6 -5
  6. data/lib/gds-sso.rb +24 -23
  7. data/lib/gds-sso/api_access.rb +1 -1
  8. data/lib/gds-sso/bearer_token.rb +24 -24
  9. data/lib/gds-sso/config.rb +9 -5
  10. data/lib/gds-sso/controller_methods.rb +5 -6
  11. data/lib/gds-sso/failure_app.rb +7 -7
  12. data/lib/gds-sso/lint/user_spec.rb +24 -25
  13. data/lib/gds-sso/lint/user_test.rb +28 -28
  14. data/lib/gds-sso/user.rb +12 -12
  15. data/lib/gds-sso/version.rb +1 -1
  16. data/lib/gds-sso/warden_config.rb +21 -31
  17. data/spec/controller/api_user_controller_spec.rb +40 -37
  18. data/spec/controller/controller_methods_spec.rb +28 -28
  19. data/spec/internal/app/controllers/application_controller.rb +1 -1
  20. data/spec/internal/app/controllers/example_controller.rb +1 -2
  21. data/spec/internal/config/initializers/gds-sso.rb +2 -2
  22. data/spec/internal/config/routes.rb +2 -2
  23. data/spec/internal/db/combustion_test.sqlite +0 -0
  24. data/spec/internal/db/schema.rb +5 -5
  25. data/spec/internal/log/test.log +1079 -1079
  26. data/spec/requests/end_to_end_spec.rb +44 -45
  27. data/spec/spec_helper.rb +12 -13
  28. data/spec/support/signon_integration_helpers.rb +9 -7
  29. data/spec/support/timecop.rb +1 -1
  30. data/spec/unit/api_access_spec.rb +7 -7
  31. data/spec/unit/bearer_token_spec.rb +14 -15
  32. data/spec/unit/config_spec.rb +5 -5
  33. data/spec/unit/mock_bearer_token_spec.rb +4 -4
  34. data/spec/unit/session_serialisation_spec.rb +5 -5
  35. data/spec/unit/user_spec.rb +22 -23
  36. metadata +71 -57
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2f6e8e343ed76d12863efbbaa32b8cad40f6f1c089e425a4e9fa3fdde95ee0c8
4
- data.tar.gz: c1556af8d9f7fb3a17708796e4ab5e63d00f57b1b05e67123eea37baacd77994
3
+ metadata.gz: a2435fe77d5992ffde6d0cb2aaf09ed4449c17c73908e4509e0a9a0ad6dc2763
4
+ data.tar.gz: fdeae2412f7a8a2f665b6d3ef8da833fc49737bab89336517b52c89bd3148cc5
5
5
  SHA512:
6
- metadata.gz: 7d6c7c78f8f04bbb7d19ed8dfb60427b0b16441206f14828f46edd46d4b94a0beab11c0b2697bc3677e0b711a9b8fcb80109b83eef7a272aca16d409be6fd831
7
- data.tar.gz: e22e4728bc10f3f4b0c0ba791566512c5b855f80666dbc76e9abea6cdf17eb52a8d77d1ab37a2e3e95042bd80f19cc3cd769e3018c6603538455602ea17a9394
6
+ metadata.gz: b5357aa5392b165604cda90222b0edd561dceff9ec8aa18da4bf40d4bf4818b65cc32b7df96f2ef8ae8a92b0e094a84e729448c4d5bd0a54a4ce1d62fbafde85
7
+ data.tar.gz: 8ad294caa8d1e2c09256f3e41e7cf380cd271d9b5c3504daef1e3e0651cba1130e9f29a92c1c66c183c373b156858d61755e998b99ab1ad125ed92906d28ce14
data/Rakefile CHANGED
@@ -1,19 +1,24 @@
1
- require 'bundler/setup'
2
- require 'bundler/gem_tasks'
1
+ require "bundler/setup"
2
+ require "bundler/gem_tasks"
3
3
 
4
4
  Bundler::GemHelper.install_tasks
5
5
 
6
- require 'rspec/core/rake_task'
6
+ require "rspec/core/rake_task"
7
7
  desc "Run all specs"
8
8
  RSpec::Core::RakeTask.new(:spec) do |task|
9
- task.pattern = 'spec/**/*_spec.rb'
9
+ task.pattern = "spec/**/*_spec.rb"
10
10
  end
11
11
 
12
12
  namespace :spec do
13
13
  desc "Run integration specs"
14
14
  RSpec::Core::RakeTask.new(:integration) do |task|
15
- task.pattern = 'spec/integration/**/*_spec.rb'
15
+ task.pattern = "spec/integration/**/*_spec.rb"
16
16
  end
17
17
  end
18
18
 
19
- task :default => ["spec"]
19
+ desc "Lint Ruby"
20
+ task :lint do
21
+ sh "bundle exec rubocop --format clang"
22
+ end
23
+
24
+ task default: %i[spec lint]
@@ -6,43 +6,45 @@ class Api::UserController < ActionController::Base
6
6
  before_action :require_user_update_permission
7
7
 
8
8
  def update
9
- user_json = JSON.parse(request.body.read)['user']
9
+ user_json = JSON.parse(request.body.read)["user"]
10
10
  oauth_hash = build_gds_oauth_hash(user_json)
11
11
  GDS::SSO::Config.user_klass.find_for_gds_oauth(oauth_hash)
12
- head :ok, content_type: 'text/plain'
12
+ head :ok, content_type: "text/plain"
13
13
  end
14
14
 
15
15
  def reauth
16
- user = GDS::SSO::Config.user_klass.where(:uid => params[:uid]).first
16
+ user = GDS::SSO::Config.user_klass.where(uid: params[:uid]).first
17
17
  if user.nil? || user.set_remotely_signed_out!
18
- head :ok, content_type: 'text/plain'
18
+ head :ok, content_type: "text/plain"
19
19
  else
20
- head 500, content_type: 'text/plain'
20
+ head 500, content_type: "text/plain"
21
21
  end
22
22
  end
23
23
 
24
- private
25
- # This should mirror the object created by the omniauth-gds strategy/gem
26
- # By doing this, we can reuse the code for creating/updating the user
27
- def build_gds_oauth_hash(user_json)
28
- OmniAuth::AuthHash.new(
29
- uid: user_json['uid'],
30
- provider: 'gds',
31
- info: {
32
- name: user_json['name'],
33
- email: user_json['email']
34
- },
35
- extra: {
36
- user: {
37
- permissions: user_json['permissions'],
38
- organisation_slug: user_json['organisation_slug'],
39
- organisation_content_id: user_json['organisation_content_id'],
40
- disabled: user_json['disabled'],
41
- }
42
- })
43
- end
24
+ private
44
25
 
45
- def require_user_update_permission
46
- authorise_user!("user_update_permission")
47
- end
26
+ # This should mirror the object created by the omniauth-gds strategy/gem
27
+ # By doing this, we can reuse the code for creating/updating the user
28
+ def build_gds_oauth_hash(user_json)
29
+ OmniAuth::AuthHash.new(
30
+ uid: user_json["uid"],
31
+ provider: "gds",
32
+ info: {
33
+ name: user_json["name"],
34
+ email: user_json["email"],
35
+ },
36
+ extra: {
37
+ user: {
38
+ permissions: user_json["permissions"],
39
+ organisation_slug: user_json["organisation_slug"],
40
+ organisation_content_id: user_json["organisation_content_id"],
41
+ disabled: user_json["disabled"],
42
+ },
43
+ },
44
+ )
45
+ end
46
+
47
+ def require_user_update_permission
48
+ authorise_user!("user_update_permission")
49
+ end
48
50
  end
@@ -1,16 +1,14 @@
1
1
  class AuthenticationsController < ActionController::Base
2
2
  include GDS::SSO::ControllerMethods
3
3
 
4
- before_action :authenticate_user!, :only => :callback
4
+ before_action :authenticate_user!, only: :callback
5
5
  layout false
6
6
 
7
7
  def callback
8
- redirect_to session["return_to"] || '/'
8
+ redirect_to session["return_to"] || "/"
9
9
  end
10
10
 
11
- def failure
12
-
13
- end
11
+ def failure; end
14
12
 
15
13
  def sign_out
16
14
  logout
@@ -1,8 +1,9 @@
1
1
  Rails.application.routes.draw do
2
2
  next if GDS::SSO::Config.api_only?
3
- get '/auth/gds/callback', to: 'authentications#callback', as: :gds_sign_in
4
- get '/auth/gds/sign_out', to: 'authentications#sign_out', as: :gds_sign_out
5
- get '/auth/failure', to: 'authentications#failure', as: :auth_failure
6
- put '/auth/gds/api/users/:uid', to: "api/user#update"
7
- post '/auth/gds/api/users/:uid/reauth', to: "api/user#reauth"
3
+
4
+ get "/auth/gds/callback", to: "authentications#callback", as: :gds_sign_in
5
+ get "/auth/gds/sign_out", to: "authentications#sign_out", as: :gds_sign_out
6
+ get "/auth/failure", to: "authentications#failure", as: :auth_failure
7
+ put "/auth/gds/api/users/:uid", to: "api/user#update"
8
+ post "/auth/gds/api/users/:uid/reauth", to: "api/user#reauth"
8
9
  end
@@ -1,17 +1,17 @@
1
- require 'rails'
1
+ require "rails"
2
2
 
3
- require 'gds-sso/config'
4
- require 'gds-sso/version'
5
- require 'gds-sso/warden_config'
6
- require 'omniauth'
7
- require 'omniauth-gds'
3
+ require "gds-sso/config"
4
+ require "gds-sso/version"
5
+ require "gds-sso/warden_config"
6
+ require "omniauth"
7
+ require "omniauth-gds"
8
8
 
9
9
  module GDS
10
10
  module SSO
11
- autoload :FailureApp, 'gds-sso/failure_app'
12
- autoload :ControllerMethods, 'gds-sso/controller_methods'
13
- autoload :User, 'gds-sso/user'
14
- autoload :ApiAccess, 'gds-sso/api_access'
11
+ autoload :FailureApp, "gds-sso/failure_app"
12
+ autoload :ControllerMethods, "gds-sso/controller_methods"
13
+ autoload :User, "gds-sso/user"
14
+ autoload :ApiAccess, "gds-sso/api_access"
15
15
 
16
16
  # User to return as logged in during tests
17
17
  mattr_accessor :test_user
@@ -23,29 +23,30 @@ module GDS
23
23
  class Engine < ::Rails::Engine
24
24
  # Force routes to be loaded if we are doing any eager load.
25
25
  # TODO - check this one - Stolen from Devise because it looked sensible...
26
- config.before_eager_load { |app| app.reload_routes! }
26
+ config.before_eager_load(&:reload_routes!)
27
27
 
28
28
  config.app_middleware.use ::OmniAuth::Builder do
29
29
  next if GDS::SSO::Config.api_only?
30
+
30
31
  provider :gds, GDS::SSO::Config.oauth_id, GDS::SSO::Config.oauth_secret,
31
- client_options: {
32
- site: GDS::SSO::Config.oauth_root_url,
33
- authorize_url: "#{GDS::SSO::Config.oauth_root_url}/oauth/authorize",
34
- token_url: "#{GDS::SSO::Config.oauth_root_url}/oauth/access_token",
35
- connection_opts: {
36
- headers: {
37
- user_agent: "gds-sso/#{GDS::SSO::VERSION} (#{ENV['GOVUK_APP_NAME']})"
38
- }
39
- }
40
- }
32
+ client_options: {
33
+ site: GDS::SSO::Config.oauth_root_url,
34
+ authorize_url: "#{GDS::SSO::Config.oauth_root_url}/oauth/authorize",
35
+ token_url: "#{GDS::SSO::Config.oauth_root_url}/oauth/access_token",
36
+ connection_opts: {
37
+ headers: {
38
+ user_agent: "gds-sso/#{GDS::SSO::VERSION} (#{ENV['GOVUK_APP_NAME']})",
39
+ },
40
+ },
41
+ }
41
42
  end
42
43
 
43
44
  def self.default_strategies
44
- Config.use_mock_strategies? ? [:mock_gds_sso, :gds_bearer_token] : [:gds_sso, :gds_bearer_token]
45
+ Config.use_mock_strategies? ? %i[mock_gds_sso gds_bearer_token] : %i[gds_sso gds_bearer_token]
45
46
  end
46
47
 
47
48
  config.app_middleware.use Warden::Manager do |config|
48
- config.default_strategies *self.default_strategies
49
+ config.default_strategies(*default_strategies)
49
50
  config.failure_app = GDS::SSO::FailureApp
50
51
  end
51
52
  end
@@ -2,7 +2,7 @@ module GDS
2
2
  module SSO
3
3
  class ApiAccess
4
4
  def self.api_call?(env)
5
- /\ABearer / === env['HTTP_AUTHORIZATION'].to_s
5
+ env["HTTP_AUTHORIZATION"].to_s =~ /\ABearer /
6
6
  end
7
7
  end
8
8
  end
@@ -1,12 +1,12 @@
1
- require 'multi_json'
2
- require 'oauth2'
3
- require 'gds-sso/version'
1
+ require "multi_json"
2
+ require "oauth2"
3
+ require "gds-sso/version"
4
4
 
5
5
  module GDS
6
6
  module SSO
7
7
  module BearerToken
8
8
  def self.locate(token_string)
9
- user_details = GDS::SSO::Config.cache.fetch(['api-user-cache', token_string], expires_in: 5.minutes) do
9
+ user_details = GDS::SSO::Config.cache.fetch(["api-user-cache", token_string], expires_in: 5.minutes) do
10
10
  access_token = OAuth2::AccessToken.new(oauth_client, token_string)
11
11
  response_body = access_token.get("/user.json?client_id=#{CGI.escape(GDS::SSO::Config.oauth_id)}").body
12
12
  omniauth_style_response(response_body)
@@ -21,12 +21,12 @@ module GDS
21
21
  @oauth_client ||= OAuth2::Client.new(
22
22
  GDS::SSO::Config.oauth_id,
23
23
  GDS::SSO::Config.oauth_secret,
24
- :site => GDS::SSO::Config.oauth_root_url,
25
- :connection_opts => {
26
- :headers => {
27
- :user_agent => "gds-sso/#{GDS::SSO::VERSION} (#{ENV['GOVUK_APP_NAME']})"
28
- }
29
- }.merge(GDS::SSO::Config.connection_opts)
24
+ site: GDS::SSO::Config.oauth_root_url,
25
+ connection_opts: {
26
+ headers: {
27
+ user_agent: "gds-sso/#{GDS::SSO::VERSION} (#{ENV['GOVUK_APP_NAME']})",
28
+ },
29
+ }.merge(GDS::SSO::Config.connection_opts),
30
30
  )
31
31
  end
32
32
 
@@ -35,32 +35,32 @@ module GDS
35
35
  # structure. Here we're addressing signon directly so
36
36
  # we need to transform the response ourselves.
37
37
  def self.omniauth_style_response(response_body)
38
- input = MultiJson.decode(response_body)['user']
38
+ input = MultiJson.decode(response_body)["user"]
39
39
 
40
40
  {
41
- 'uid' => input['uid'],
42
- 'info' => {
43
- 'email' => input['email'],
44
- 'name' => input['name']
41
+ "uid" => input["uid"],
42
+ "info" => {
43
+ "email" => input["email"],
44
+ "name" => input["name"],
45
+ },
46
+ "extra" => {
47
+ "user" => {
48
+ "permissions" => input["permissions"],
49
+ "organisation_slug" => input["organisation_slug"],
50
+ "organisation_content_id" => input["organisation_content_id"],
51
+ },
45
52
  },
46
- 'extra' => {
47
- 'user' => {
48
- 'permissions' => input['permissions'],
49
- 'organisation_slug' => input['organisation_slug'],
50
- 'organisation_content_id' => input['organisation_content_id'],
51
- }
52
- }
53
53
  }
54
54
  end
55
55
  end
56
56
 
57
57
  module MockBearerToken
58
- def self.locate(token_string)
58
+ def self.locate(_token_string)
59
59
  dummy_api_user = GDS::SSO.test_user || GDS::SSO::Config.user_klass.where(email: "dummyapiuser@domain.com").first
60
60
  if dummy_api_user.nil?
61
61
  dummy_api_user = GDS::SSO::Config.user_klass.new
62
62
  dummy_api_user.email = "dummyapiuser@domain.com"
63
- dummy_api_user.uid = "#{rand(10000)}"
63
+ dummy_api_user.uid = rand(10_000).to_s
64
64
  dummy_api_user.name = "Dummy API user created by gds-sso"
65
65
  end
66
66
 
@@ -1,8 +1,10 @@
1
- require 'active_support/cache/null_store'
1
+ require "active_support/cache/null_store"
2
2
 
3
3
  module GDS
4
4
  module SSO
5
5
  module Config
6
+ # rubocop:disable Style/ClassVars
7
+
6
8
  # Name of the User class
7
9
  mattr_accessor :user_model
8
10
  @@user_model = "User"
@@ -29,13 +31,13 @@ module GDS
29
31
 
30
32
  mattr_accessor :connection_opts
31
33
  @@connection_opts = {
32
- :request => {
33
- :open_timeout => 5,
34
- }
34
+ request: {
35
+ open_timeout: 5,
36
+ },
35
37
  }
36
38
 
37
39
  def self.permissions_for_dummy_api_user
38
- ["signin"].push(*additional_mock_permissions_required)
40
+ %w[signin].push(*additional_mock_permissions_required)
39
41
  end
40
42
 
41
43
  def self.user_klass
@@ -57,6 +59,8 @@ module GDS
57
59
  default = config.respond_to?(:api_only) ? config.api_only : false
58
60
  @@api_only.nil? ? default : @@api_only
59
61
  end
62
+
63
+ # rubocop:enable Style/ClassVars
60
64
  end
61
65
  end
62
66
  end
@@ -19,7 +19,6 @@ module GDS
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.
@@ -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