Skip to content

Commit

Permalink
NAS-125057 / 24.04 / Add support for NFS roles (#12484)
Browse files Browse the repository at this point in the history
* Add support for NFS roles
Add tests for the new NFS roles

* Commented out add_principal WRITE test as it requires AD configuration.
  • Loading branch information
mgrimesix authored Nov 13, 2023
1 parent e06772b commit 614f23d
Show file tree
Hide file tree
Showing 4 changed files with 31 additions and 5 deletions.
1 change: 1 addition & 0 deletions src/middlewared/middlewared/plugins/nfs.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ class Config:
datastore_prefix = "nfs_srv_"
datastore_extend = 'nfs.nfs_extend'
cli_namespace = "service.nfs"
role_prefix = "SHARING_NFS"

ENTRY = Dict(
'nfs_entry',
Expand Down
2 changes: 1 addition & 1 deletion src/middlewared/middlewared/plugins/nfs_/krb5.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ async def add_principal_ldap(self, data):
raise CallError('This feature has not yet been implemented for '
'the LDAP directory service.', errno=errno.ENOSYS)

@accepts(Ref('kerberos_username_password'))
@accepts(Ref('kerberos_username_password'), roles=['SHARING_NFS_WRITE'])
@returns(Bool('principal_add_status'))
async def add_principal(self, data):
"""
Expand Down
8 changes: 5 additions & 3 deletions src/middlewared/middlewared/plugins/nfs_/status.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ def get_rmtab(self):

return entries

@filterable
# NFS_WRITE because this exposes hostnames and IP addresses
@filterable(roles=['SHARING_NFS_WRITE'])
def get_nfs3_clients(self, filters, options):
"""
Read contents of rmtab. This information may not
Expand Down Expand Up @@ -68,7 +69,8 @@ def get_nfs4_client_states(self, id_):
# return empty list in this case
return states or []

@filterable
# NFS_WRITE because this exposes hostnames, IP addresses and other details
@filterable(roles=['SHARING_NFS_WRITE'])
@filterable_returns(Dict(
'client',
Str('id'),
Expand Down Expand Up @@ -155,7 +157,7 @@ def get_nfs4_clients(self, filters, options):

return filter_list(clients, filters, options)

@accepts()
@accepts(roles=['SHARING_NFS_READ'])
@returns(Int('number_of_clients'))
def client_count(self):
"""
Expand Down
25 changes: 24 additions & 1 deletion tests/api2/test_nfs_share_crud_roles.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@
from middlewared.test.integration.assets.pool import dataset
from middlewared.test.integration.assets.account import unprivileged_user_client

try:
from config import ADPASSWORD, ADUSERNAME
except ImportError:
Reason = 'ADPASSWORD, or/and ADUSERNAME are missing in config.py"'
pytestmark = pytest.mark.skip(reason=Reason)


@pytest.fixture(scope="module")
def ds():
Expand All @@ -25,6 +31,7 @@ def share():
def test_read_role_can_read(role):
with unprivileged_user_client(roles=[role]) as c:
c.call("sharing.nfs.query")
c.call("nfs.client_count")


@pytest.mark.parametrize("role", ["SHARING_READ", "SHARING_NFS_READ"])
Expand All @@ -42,12 +49,28 @@ def test_read_role_cant_write(ds, share, role):
c.call("sharing.nfs.delete", share["id"])
assert ve.value.errno == errno.EACCES

with pytest.raises(ClientException) as ve:
c.call("nfs.get_nfs3_clients")
assert ve.value.errno == errno.EACCES

with pytest.raises(ClientException) as ve:
c.call("nfs.get_nfs4_clients")
assert ve.value.errno == errno.EACCES

# This should be blocked before needing to mock any configuration
with pytest.raises(ClientException) as ve:
c.call("nfs.add_principal", {"username": ADUSERNAME, "password": ADPASSWORD})
assert ve.value.errno == errno.EACCES


@pytest.mark.parametrize("role", ["SHARING_WRITE", "SHARING_NFS_WRITE"])
def test_write_role_can_write(ds, role):
with unprivileged_user_client(roles=[role]) as c:
share = c.call("sharing.nfs.create", {"path": f"/mnt/{ds}"})

c.call("sharing.nfs.update", share["id"], {})

c.call("sharing.nfs.delete", share["id"])
c.call("nfs.get_nfs3_clients")
c.call("nfs.get_nfs4_clients")
# Multiple layers of dependencies to mock up this as a successful write
# c.call("nfs.add_principal", {"username": ADUSERNAME, "password": ADPASSWORD})

0 comments on commit 614f23d

Please sign in to comment.