Skip to content

Commit 0597235

Browse files
committed
rquota: add stub for rquota service
Motivation: Add server stub for remote quota management protocol. Added test case for permission check. Result: Servers can provide rquota support if needed. Fixes: #133 Acked-by: Lea Morschel Target: master
1 parent c4cb94d commit 0597235

File tree

4 files changed

+253
-2
lines changed

4 files changed

+253
-2
lines changed

rquota/pom.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
<version>0.26.0-SNAPSHOT</version>
99
</parent>
1010

11-
<groupId>org.dcache</groupId>
1211
<artifactId>rquota</artifactId>
1312
<packaging>jar</packaging>
1413
<description>Remote quota protocol implementation</description>
@@ -43,7 +42,8 @@
4342
</dependency>
4443
<dependency>
4544
<groupId>org.dcache</groupId>
46-
<artifactId>oncrpc4j-core</artifactId>
45+
<artifactId>nfs4j-core</artifactId>
46+
<version>${project.version}</version>
4747
</dependency>
4848
</dependencies>
4949

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
/*
2+
* Copyright (c) 2024 Deutsches Elektronen-Synchroton,
3+
* Member of the Helmholtz Association, (DESY), HAMBURG, GERMANY
4+
*
5+
* This library is free software; you can redistribute it and/or modify
6+
* it under the terms of the GNU Library General Public License as
7+
* published by the Free Software Foundation; either version 2 of the
8+
* License, or (at your option) any later version.
9+
*
10+
* This library is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
* GNU Library General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU Library General Public
16+
* License along with this program (see the file COPYING.LIB for more
17+
* details); if not, write to the Free Software Foundation, Inc.,
18+
* 675 Mass Ave, Cambridge, MA 02139, USA.
19+
*/
20+
package org.dcache.rquota;
21+
22+
import static org.dcache.rquota.QuotaVfs.GROUP_QUOTA;
23+
import static org.dcache.rquota.QuotaVfs.USER_QUOTA;
24+
import org.dcache.nfs.util.SubjectHolder;
25+
import org.dcache.nfs.util.UnixSubjects;
26+
import org.dcache.oncrpc4j.rpc.RpcCall;
27+
import org.dcache.rquota.xdr.ext_getquota_args;
28+
import org.dcache.rquota.xdr.ext_setquota_args;
29+
import org.dcache.rquota.xdr.getquota_args;
30+
import org.dcache.rquota.xdr.getquota_rslt;
31+
import org.dcache.rquota.xdr.qr_status;
32+
import org.dcache.rquota.xdr.rquotaServerStub;
33+
import org.dcache.rquota.xdr.setquota_args;
34+
import org.dcache.rquota.xdr.setquota_rslt;
35+
import org.slf4j.Logger;
36+
37+
import javax.security.auth.Subject;
38+
39+
public class QuotaSvc extends rquotaServerStub {
40+
41+
private final static Logger LOGGER = org.slf4j.LoggerFactory.getLogger(QuotaSvc.class);
42+
43+
private final QuotaVfs _qfs;
44+
45+
public QuotaSvc(QuotaVfs _qfs) {
46+
this._qfs = _qfs;
47+
}
48+
49+
@Override
50+
public getquota_rslt RQUOTAPROC_GETQUOTA_1(RpcCall call$, getquota_args arg1) {
51+
throw new UnsupportedOperationException("Not supported yet.");
52+
}
53+
54+
@Override
55+
public getquota_rslt RQUOTAPROC_GETACTIVEQUOTA_1(RpcCall call$, getquota_args arg1) {
56+
throw new UnsupportedOperationException("Not supported yet.");
57+
}
58+
59+
@Override
60+
public setquota_rslt RQUOTAPROC_SETQUOTA_1(RpcCall call$, setquota_args arg1) {
61+
throw new UnsupportedOperationException("Not supported yet.");
62+
}
63+
64+
@Override
65+
public setquota_rslt RQUOTAPROC_SETACTIVEQUOTA_1(RpcCall call$, setquota_args arg1) {
66+
throw new UnsupportedOperationException("Not supported yet.");
67+
}
68+
69+
@Override
70+
public getquota_rslt RQUOTAPROC_GETQUOTA_2(RpcCall call$, ext_getquota_args arg1) {
71+
var r = new getquota_rslt();
72+
73+
if (!canQuery(call$.getCredential().getSubject(), arg1.gqa_id, arg1.gqa_type)) {
74+
r.status = qr_status.Q_EPERM;
75+
return r;
76+
}
77+
78+
r.status = qr_status.Q_OK;
79+
r.gqr_rquota = _qfs.getQuota(arg1.gqa_id, arg1.gqa_type);
80+
return r;
81+
}
82+
83+
@Override
84+
public getquota_rslt RQUOTAPROC_GETACTIVEQUOTA_2(RpcCall call$, ext_getquota_args arg1) {
85+
var r = new getquota_rslt();
86+
87+
if (!canQuery(call$.getCredential().getSubject(), arg1.gqa_id, arg1.gqa_type)) {
88+
r.status = qr_status.Q_EPERM;
89+
return r;
90+
}
91+
92+
r.status = qr_status.Q_OK;
93+
r.gqr_rquota = _qfs.getQuota(arg1.gqa_id, arg1.gqa_type);
94+
return r;
95+
}
96+
97+
@Override
98+
public setquota_rslt RQUOTAPROC_SETQUOTA_2(RpcCall call$, ext_setquota_args arg1) {
99+
throw new UnsupportedOperationException("Not supported yet.");
100+
}
101+
102+
@Override
103+
public setquota_rslt RQUOTAPROC_SETACTIVEQUOTA_2(RpcCall call$, ext_setquota_args arg1) {
104+
throw new UnsupportedOperationException("Not supported yet.");
105+
}
106+
107+
/**
108+
* Check if the given subject can query the quota for the given id and type.
109+
*
110+
* @param subject the subject to check
111+
* @param id the id to check
112+
* @param type the type to check
113+
* @return true if the subject can query the quota, false otherwise
114+
*/
115+
private boolean canQuery(Subject subject, int id, int type) {
116+
117+
boolean canQuery = UnixSubjects.isRootSubject(subject) ||
118+
(type == USER_QUOTA && UnixSubjects.hasUid(subject, id)) ||
119+
(type == GROUP_QUOTA && UnixSubjects.hasGid(subject, id));
120+
121+
LOGGER.debug("Request by {} to query quota for id {} and type {}: {}",
122+
new SubjectHolder(subject), id, type, canQuery ? "granted" : "denied");
123+
return canQuery;
124+
}
125+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/*
2+
* Copyright (c) 2024 Deutsches Elektronen-Synchroton,
3+
* Member of the Helmholtz Association, (DESY), HAMBURG, GERMANY
4+
*
5+
* This library is free software; you can redistribute it and/or modify
6+
* it under the terms of the GNU Library General Public License as
7+
* published by the Free Software Foundation; either version 2 of the
8+
* License, or (at your option) any later version.
9+
*
10+
* This library is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
* GNU Library General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU Library General Public
16+
* License along with this program (see the file COPYING.LIB for more
17+
* details); if not, write to the Free Software Foundation, Inc.,
18+
* 675 Mass Ave, Cambridge, MA 02139, USA.
19+
*/
20+
package org.dcache.rquota;
21+
22+
import org.dcache.rquota.xdr.rquota;
23+
24+
/**
25+
* Interface for querying quotas.
26+
*/
27+
public interface QuotaVfs {
28+
29+
/**
30+
* User quota type.
31+
*/
32+
int USER_QUOTA = 0;
33+
34+
/**
35+
* Group quota type.
36+
*/
37+
int GROUP_QUOTA = 1;
38+
39+
/**
40+
* Get the quota for the given id.
41+
*
42+
* @param id numeric id of user or group to get quota for.
43+
* @param type type of quota to get, either {@link #USER_QUOTA} or {@link #GROUP_QUOTA}.
44+
* @return the quota for the given subject
45+
*/
46+
rquota getQuota(int id, int type);
47+
}
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
package org.dcache.rquota;
2+
3+
import static org.dcache.rquota.QuotaVfs.GROUP_QUOTA;
4+
import static org.dcache.rquota.QuotaVfs.USER_QUOTA;
5+
import static org.junit.Assert.*;
6+
import static org.mockito.Mockito.mock;
7+
import org.dcache.nfs.util.UnixSubjects;
8+
import org.dcache.oncrpc4j.rpc.RpcAuth;
9+
import org.dcache.oncrpc4j.rpc.RpcCall;
10+
import org.dcache.rquota.xdr.ext_getquota_args;
11+
import org.dcache.rquota.xdr.getquota_rslt;
12+
import org.dcache.rquota.xdr.qr_status;
13+
import org.junit.Before;
14+
import org.junit.Test;
15+
import org.mockito.Mockito;
16+
17+
public class QuotaSvcTest {
18+
19+
private QuotaVfs quotaVfs;
20+
private QuotaSvc quotaSvc;
21+
private RpcCall call;
22+
private RpcAuth auth;
23+
24+
@Before
25+
public void setUp() {
26+
quotaVfs = mock(QuotaVfs.class);
27+
quotaSvc = new QuotaSvc(quotaVfs);
28+
call = mock(RpcCall.class);
29+
auth = mock(RpcAuth.class);
30+
}
31+
32+
@Test
33+
public void testGetQuotaWrongUser() {
34+
ext_getquota_args args = new ext_getquota_args();
35+
args.gqa_id = 1;
36+
args.gqa_type = USER_QUOTA;
37+
38+
Mockito.when(call.getCredential()).thenReturn(auth);
39+
Mockito.when(auth.getSubject()).thenReturn(UnixSubjects.toSubject(2, 2));
40+
getquota_rslt result = quotaSvc.RQUOTAPROC_GETQUOTA_2(call, args);
41+
assertEquals(qr_status.Q_EPERM, result.status);
42+
}
43+
44+
@Test
45+
public void testGetQuotaWrongGroup() {
46+
ext_getquota_args args = new ext_getquota_args();
47+
args.gqa_id = 1;
48+
args.gqa_type = GROUP_QUOTA;
49+
50+
Mockito.when(call.getCredential()).thenReturn(auth);
51+
Mockito.when(auth.getSubject()).thenReturn(UnixSubjects.toSubject(2, 2));
52+
getquota_rslt result = quotaSvc.RQUOTAPROC_GETQUOTA_2(call, args);
53+
assertEquals(qr_status.Q_EPERM, result.status);
54+
}
55+
56+
@Test
57+
public void testGetUserQuota() {
58+
ext_getquota_args args = new ext_getquota_args();
59+
args.gqa_id = 1;
60+
args.gqa_type = USER_QUOTA;
61+
62+
Mockito.when(call.getCredential()).thenReturn(auth);
63+
Mockito.when(auth.getSubject()).thenReturn(UnixSubjects.toSubject(1, 1));
64+
getquota_rslt result = quotaSvc.RQUOTAPROC_GETQUOTA_2(call, args);
65+
assertEquals(qr_status.Q_OK, result.status);
66+
}
67+
68+
@Test
69+
public void testGetGroupQuota() {
70+
ext_getquota_args args = new ext_getquota_args();
71+
args.gqa_id = 1;
72+
args.gqa_type = GROUP_QUOTA;
73+
74+
Mockito.when(call.getCredential()).thenReturn(auth);
75+
Mockito.when(auth.getSubject()).thenReturn(UnixSubjects.toSubject(1, 1));
76+
getquota_rslt result = quotaSvc.RQUOTAPROC_GETQUOTA_2(call, args);
77+
assertEquals(qr_status.Q_OK, result.status);
78+
}
79+
}

0 commit comments

Comments
 (0)