-
Notifications
You must be signed in to change notification settings - Fork 16
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Extract the user authorisation logic into a separate class
- All the logic that checks the current_user permissions has been extracted to a separate class, because it will need to be re-used from different parts of the code.
- Loading branch information
Alex Avlonitis
committed
Apr 29, 2024
1 parent
40afea5
commit 2fa18d8
Showing
4 changed files
with
120 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
module GDS | ||
module SSO | ||
class AuthoriseUser | ||
def self.call(...) = new(...).call | ||
|
||
def initialize(current_user, permissions) | ||
@current_user = current_user | ||
@permissions = permissions | ||
end | ||
|
||
def call | ||
case permissions | ||
when String | ||
unless current_user.has_permission?(permissions) | ||
raise GDS::SSO::PermissionDeniedError, "Sorry, you don't seem to have the #{permissions} permission for this app." | ||
end | ||
when Hash | ||
raise ArgumentError, "Must be either `any_of` or `all_of`" unless permissions.keys.size == 1 | ||
|
||
if permissions[:any_of] | ||
authorise_user_with_at_least_one_of_permissions!(permissions[:any_of]) | ||
elsif permissions[:all_of] | ||
authorise_user_with_all_permissions!(permissions[:all_of]) | ||
else | ||
raise ArgumentError, "Must be either `any_of` or `all_of`" | ||
end | ||
end | ||
end | ||
|
||
private | ||
|
||
attr_reader :current_user, :permissions | ||
|
||
def authorise_user_with_at_least_one_of_permissions!(permissions) | ||
if permissions.none? { |permission| current_user.has_permission?(permission) } | ||
raise GDS::SSO::PermissionDeniedError, | ||
"Sorry, you don't seem to have any of the permissions: #{permissions.to_sentence} for this app." | ||
end | ||
end | ||
|
||
def authorise_user_with_all_permissions!(permissions) | ||
unless permissions.all? { |permission| current_user.has_permission?(permission) } | ||
raise GDS::SSO::PermissionDeniedError, | ||
"Sorry, you don't seem to have all of the permissions: #{permissions.to_sentence} for this app." | ||
end | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
require "spec_helper" | ||
require "gds-sso/authorise_user" | ||
|
||
describe GDS::SSO::AuthoriseUser do | ||
describe "#call" do | ||
let(:current_user) { double } | ||
|
||
context "with a single string permission argument" do | ||
let(:permissions) { "admin" } | ||
let(:expected_error) { GDS::SSO::PermissionDeniedError } | ||
|
||
it "permits users with the required permission" do | ||
allow(current_user).to receive(:has_permission?).with("admin").and_return(true) | ||
|
||
expect { described_class.call(current_user, permissions) }.not_to raise_error | ||
end | ||
|
||
it "does not permit the users without the required permission" do | ||
allow(current_user).to receive(:has_permission?).with("admin").and_return(false) | ||
|
||
expect { described_class.call(current_user, permissions) }.to raise_error(expected_error) | ||
end | ||
end | ||
|
||
context "with the `all_of` option" do | ||
let(:permissions) { { all_of: %w[admin editor] } } | ||
let(:expected_error) { GDS::SSO::PermissionDeniedError } | ||
|
||
it "permits users with all of the required permissions" do | ||
allow(current_user).to receive(:has_permission?).with("admin").and_return(true) | ||
allow(current_user).to receive(:has_permission?).with("editor").and_return(true) | ||
|
||
expect { described_class.call(current_user, permissions) }.not_to raise_error | ||
end | ||
|
||
it "does not permit users without all of the required permissions" do | ||
allow(current_user).to receive(:has_permission?).with("admin").and_return(false) | ||
allow(current_user).to receive(:has_permission?).with("editor").and_return(true) | ||
|
||
expect { described_class.call(current_user, permissions) }.to raise_error(expected_error) | ||
end | ||
end | ||
|
||
context "with the `any_of` option" do | ||
let(:permissions) { { any_of: %w[admin editor] } } | ||
let(:expected_error) { GDS::SSO::PermissionDeniedError } | ||
|
||
it "permits users with any of the required permissions" do | ||
allow(current_user).to receive(:has_permission?).with("admin").and_return(true) | ||
allow(current_user).to receive(:has_permission?).with("editor").and_return(false) | ||
|
||
expect { described_class.call(current_user, permissions) }.not_to raise_error | ||
end | ||
|
||
it "does not permit users without any of the required permissions" do | ||
allow(current_user).to receive(:has_permission?).and_return(false) | ||
|
||
expect { described_class.call(current_user, permissions) }.to raise_error(expected_error) | ||
end | ||
end | ||
|
||
context "with none of `any_of` or `all_of`" do | ||
it "raises an `ArgumentError`" do | ||
expect { described_class.call(current_user, { admin: true }) } | ||
.to raise_error(ArgumentError) | ||
end | ||
end | ||
end | ||
end |