Skip to content

Commit b823b9f

Browse files
committed
Merge pull request #26 from dcrissman/insert-roles
fixes #18 takes roles into account when performing insert actions
2 parents 8b8bb1a + 1c433f0 commit b823b9f

File tree

7 files changed

+231
-29
lines changed

7 files changed

+231
-29
lines changed

lightblue-ldap-crud/src/main/java/com/redhat/lightblue/crud/ldap/LdapCRUDController.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
import com.redhat.lightblue.crud.CRUDOperationContext;
4242
import com.redhat.lightblue.crud.CRUDSaveResponse;
4343
import com.redhat.lightblue.crud.CRUDUpdateResponse;
44+
import com.redhat.lightblue.crud.CrudConstants;
4445
import com.redhat.lightblue.crud.DocCtx;
4546
import com.redhat.lightblue.crud.ldap.translator.FilterTranslator;
4647
import com.redhat.lightblue.crud.ldap.translator.ResultTranslator;
@@ -64,6 +65,7 @@
6465
import com.redhat.lightblue.query.QueryExpression;
6566
import com.redhat.lightblue.query.Sort;
6667
import com.redhat.lightblue.query.UpdateExpression;
68+
import com.redhat.lightblue.util.Error;
6769
import com.redhat.lightblue.util.JsonDoc;
6870
import com.redhat.lightblue.util.Path;
6971
import com.unboundid.ldap.sdk.Attribute;
@@ -115,7 +117,17 @@ public CRUDInsertionResponse insert(CRUDOperationContext ctx,
115117
throw new RuntimeException("Unable to establish connection to LDAP", e);
116118
}
117119

120+
FieldAccessRoleEvaluator roles = new FieldAccessRoleEvaluator(md, ctx.getCallerRoles());
121+
118122
for(DocCtx document : documents){
123+
List<Path> paths = roles.getInaccessibleFields_Insert(document);
124+
if((paths != null) && !paths.isEmpty()){
125+
for(Path path : paths){
126+
document.addError(Error.get("insert", CrudConstants.ERR_NO_FIELD_INSERT_ACCESS, path.toString()));
127+
continue;
128+
}
129+
}
130+
119131
JsonNode rootNode = document.getRoot();
120132

121133
JsonNode uniqueNode = rootNode.get(store.getUniqueField());

lightblue-ldap-integration-test/src/test/java/com/redhat/lightblue/crud/ldap/ITCaseLdapCRUDControllerTest.java

Lines changed: 143 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,17 @@
1818
*/
1919
package com.redhat.lightblue.crud.ldap;
2020

21+
import static com.redhat.lightblue.util.JsonUtils.json;
2122
import static com.redhat.lightblue.util.test.AbstractJsonNodeTest.loadJsonNode;
23+
import static com.redhat.lightblue.util.test.AbstractJsonNodeTest.loadResource;
2224
import static org.junit.Assert.assertEquals;
2325
import static org.junit.Assert.assertNotNull;
26+
import static org.junit.Assert.assertNull;
2427

2528
import java.io.IOException;
29+
import java.util.Arrays;
2630

31+
import org.apache.commons.lang.StringUtils;
2732
import org.junit.AfterClass;
2833
import org.junit.BeforeClass;
2934
import org.junit.ClassRule;
@@ -48,19 +53,24 @@
4853
import com.redhat.lightblue.metadata.Metadata;
4954
import com.redhat.lightblue.mongo.test.MongoServerExternalResource;
5055
import com.redhat.lightblue.mongo.test.MongoServerExternalResource.InMemoryMongoServer;
56+
import com.redhat.lightblue.test.FakeClientIdentification;
5157
import com.redhat.lightblue.util.Error;
58+
import com.unboundid.ldap.sdk.Attribute;
5259

5360
/**
54-
* <b>NOTE:</b> This test suite is intended to be run in a certain order. Selectivly running unit tests
61+
* <b>NOTE:</b> This test suite is intended to be run in a certain order. Selectively running unit tests
5562
* may produce unwanted results.
5663
*
57-
* @author dcrissma
64+
* @author dcrissman
5865
*/
5966
@InMemoryLdapServer
6067
@InMemoryMongoServer
6168
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
6269
public class ITCaseLdapCRUDControllerTest{
6370

71+
private static final String BASEDB_USERS = "ou=Users,dc=example,dc=com";
72+
private static final String BASEDB_DEPARTMENTS = "ou=Departments,dc=example,dc=com";
73+
6474
@ClassRule
6575
public static LdapServerExternalResource ldapServer = LdapServerExternalResource.createDefaultInstance();
6676

@@ -74,10 +84,20 @@ public class ITCaseLdapCRUDControllerTest{
7484

7585
@BeforeClass
7686
public static void beforeClass() throws Exception {
87+
ldapServer.add("ou=Users,dc=example,dc=com", new Attribute[]{
88+
new Attribute("objectClass", "top"),
89+
new Attribute("objectClass", "organizationalUnit"),
90+
new Attribute("ou", "Users")});
91+
ldapServer.add("ou=Departments,dc=example,dc=com", new Attribute[]{
92+
new Attribute("objectClass", "top"),
93+
new Attribute("objectClass", "organizationalUnit"),
94+
new Attribute("ou", "Departments")});
95+
7796
System.setProperty("ldap.host", "localhost");
7897
System.setProperty("ldap.port", String.valueOf(LdapServerExternalResource.DEFAULT_PORT));
7998
System.setProperty("ldap.database", "test");
80-
System.setProperty("ldap.person.basedn", "dc=example,dc=com");
99+
System.setProperty("ldap.person.basedn", BASEDB_USERS);
100+
System.setProperty("ldap.department.basedn", BASEDB_DEPARTMENTS);
81101

82102
System.setProperty("mongo.host", "localhost");
83103
System.setProperty("mongo.port", String.valueOf(MongoServerExternalResource.DEFAULT_PORT));
@@ -90,6 +110,7 @@ public static void beforeClass() throws Exception {
90110

91111
Metadata metadata = lightblueFactory.getMetadata();
92112
metadata.createNewMetadata(tx.parse(EntityMetadata.class, loadJsonNode("./metadata/person-metadata.json")));
113+
metadata.createNewMetadata(tx.parse(EntityMetadata.class, loadJsonNode("./metadata/department-metadata.json")));
93114
}
94115

95116
@AfterClass
@@ -103,84 +124,186 @@ private void assertNoErrors(Response response){
103124
e.printStackTrace();
104125
collector.addError(e);
105126
}
127+
}
106128

129+
private void assertNoDataErrors(Response response){
107130
for(DataError error : response.getDataErrors()){
108-
Exception e = new Exception("DataError: " + error.toJson().asText());
131+
Exception e = new Exception("DataError: " + error.toJson().toString());
109132
e.printStackTrace();
110133
collector.addError(e);
111134
}
112135
}
113136

114-
private <T> T createRequest(Class<T> type, String jsonFile) throws IOException{
137+
private <T> T createRequest_FromResource(Class<T> type, String jsonFile) throws IOException{
138+
return createRequest(type, loadJsonNode(jsonFile));
139+
}
140+
141+
private <T> T createRequest_FromJsonString(Class<T> type, String jsonString) throws IOException{
142+
return createRequest(type, json(jsonString));
143+
}
144+
145+
private <T> T createRequest(Class<T> type, JsonNode node) throws IOException{
115146
JsonTranslator tx = lightblueFactory.getJsonTranslator();
116-
return tx.parse(type, loadJsonNode(jsonFile));
147+
return tx.parse(type, node);
117148
}
118149

119150
@Test
120-
public void step1Insert() throws Exception{
151+
public void series1_phase1_Person_Insert() throws Exception{
121152
Response response = lightblueFactory.getMediator().insert(
122-
createRequest(InsertionRequest.class, "./crud/insert/person-insert-many.json"));
153+
createRequest_FromResource(InsertionRequest.class, "./crud/insert/person-insert-many.json"));
123154

124155
assertNotNull(response);
125156
assertNoErrors(response);
157+
assertNoDataErrors(response);
126158
assertEquals(4, response.getModifiedCount());
127159

128160
JsonNode entityData = response.getEntityData();
129161
assertNotNull(entityData);
130162
JSONAssert.assertEquals(
131-
"[{\"dn\":\"uid=junior.doe,dc=example,dc=com\"},{\"dn\":\"uid=john.doe,dc=example,dc=com\"},{\"dn\":\"uid=jane.doe,dc=example,dc=com\"},{\"dn\":\"uid=jack.buck,dc=example,dc=com\"}]",
163+
"[{\"dn\":\"uid=junior.doe," + BASEDB_USERS + "\"},{\"dn\":\"uid=john.doe," + BASEDB_USERS + "\"},{\"dn\":\"uid=jane.doe," + BASEDB_USERS + "\"},{\"dn\":\"uid=jack.buck," + BASEDB_USERS + "\"}]",
132164
entityData.toString(), false);
133165
}
134166

135167
@Test
136-
public void step2FindSingle() throws Exception{
168+
public void series1_phase2_Person_FindSingle() throws Exception{
137169
Response response = lightblueFactory.getMediator().find(
138-
createRequest(FindRequest.class, "./crud/find/person-find-single.json"));
170+
createRequest_FromResource(FindRequest.class, "./crud/find/person-find-single.json"));
139171

140172
assertNotNull(response);
141173
assertNoErrors(response);
174+
assertNoDataErrors(response);
142175
assertEquals(1, response.getMatchCount());
143176

144177
JsonNode entityData = response.getEntityData();
145178
assertNotNull(entityData);
146179
JSONAssert.assertEquals(
147-
"[{\"dn\":\"uid=john.doe,dc=example,dc=com\",\"uid\":\"john.doe\",\"objectType\":\"person\",\"objectClass#\":4}]",
148-
entityData.toString(), false);
180+
"[{\"dn\":\"uid=john.doe," + BASEDB_USERS + "\",\"uid\":\"john.doe\",\"objectType\":\"person\",\"objectClass#\":4}]",
181+
entityData.toString(), true);
149182
}
150183

151184
@Test
152-
public void step2FindMany() throws Exception{
185+
public void series1_phase2_Person_FindMany() throws Exception{
153186
Response response = lightblueFactory.getMediator().find(
154-
createRequest(FindRequest.class, "./crud/find/person-find-many.json"));
187+
createRequest_FromResource(FindRequest.class, "./crud/find/person-find-many.json"));
155188

156189
assertNotNull(response);
157190
assertNoErrors(response);
191+
assertNoDataErrors(response);
158192
assertEquals(3, response.getMatchCount());
159193

160194
JsonNode entityData = response.getEntityData();
161195
assertNotNull(entityData);
162196

163197
//Search requests results in desc order, strict mode is enforced to assure this.
164198
JSONAssert.assertEquals(
165-
"[{\"dn\":\"uid=junior.doe,dc=example,dc=com\"},{\"dn\":\"uid=john.doe,dc=example,dc=com\"},{\"dn\":\"uid=jane.doe,dc=example,dc=com\"}]",
199+
"[{\"dn\":\"uid=junior.doe," + BASEDB_USERS + "\"},{\"dn\":\"uid=john.doe," + BASEDB_USERS + "\"},{\"dn\":\"uid=jane.doe," + BASEDB_USERS + "\"}]",
166200
entityData.toString(), true);
167201
}
168202

169203
@Test
170-
public void step2FindMany_WithPagination() throws Exception{
204+
public void series1_phase2_Person_FindMany_WithPagination() throws Exception{
171205
Response response = lightblueFactory.getMediator().find(
172-
createRequest(FindRequest.class, "./crud/find/person-find-many-paginated.json"));
206+
createRequest_FromResource(FindRequest.class, "./crud/find/person-find-many-paginated.json"));
173207

174208
assertNotNull(response);
175209
assertNoErrors(response);
210+
assertNoDataErrors(response);
176211
assertEquals(1, response.getMatchCount());
177212

178213
JsonNode entityData = response.getEntityData();
179214
assertNotNull(entityData);
180215

181216
JSONAssert.assertEquals(
182-
"[{\"dn\":\"uid=john.doe,dc=example,dc=com\"}]",
183-
entityData.toString(), false);
217+
"[{\"dn\":\"uid=john.doe," + BASEDB_USERS + "\"}]",
218+
entityData.toString(), true);
219+
}
220+
221+
@Test
222+
public void series2_phase1_Department_InsertWithRoles() throws Exception{
223+
String insert = loadResource("./crud/insert/department-insert-template.json")
224+
.replaceFirst("#cn", "Marketing")
225+
.replaceFirst("#description", "Department devoted to Marketing")
226+
.replaceFirst("#members", "\"" + StringUtils.join(Arrays.asList("cn=John Doe," + BASEDB_USERS, "cn=Jane Doe," + BASEDB_USERS), "\",\"") + "\"");
227+
228+
InsertionRequest insertRequest = createRequest_FromJsonString(InsertionRequest.class, insert);
229+
insertRequest.setClientId(new FakeClientIdentification("fakeUser", "admin"));
230+
231+
Response response = lightblueFactory.getMediator().insert(insertRequest);
232+
233+
assertNotNull(response);
234+
assertNoErrors(response);
235+
assertNoDataErrors(response);
236+
assertEquals(1, response.getModifiedCount());
237+
238+
JsonNode entityData = response.getEntityData();
239+
assertNotNull(entityData);
240+
JSONAssert.assertEquals(
241+
"[{\"dn\":\"cn=Marketing," + BASEDB_DEPARTMENTS + "\"}]",
242+
entityData.toString(), true);
243+
}
244+
245+
@Test
246+
public void series2_phase1_Department_InsertWithInvalidRoles() throws Exception{
247+
String insert = loadResource("./crud/insert/department-insert-template.json")
248+
.replaceFirst("#cn", "HR")
249+
.replaceFirst("#description", "Department devoted to HR")
250+
.replaceFirst("#members", "\"cn=John Doe," + BASEDB_USERS + "\"");
251+
252+
InsertionRequest insertRequest = createRequest_FromJsonString(InsertionRequest.class, insert);
253+
insertRequest.setClientId(new FakeClientIdentification("fakeUser"));
254+
255+
Response response = lightblueFactory.getMediator().insert(insertRequest);
256+
257+
assertNotNull(response);
258+
assertEquals(0, response.getModifiedCount());
259+
260+
assertNull(response.getEntityData());
261+
262+
assertNoErrors(response);
263+
assertEquals(1, response.getDataErrors().size());
264+
JSONAssert.assertEquals("{\"errors\":[{\"errorCode\":\"crud:insert:NoFieldAccess\",\"msg\":\"member\"}]}",
265+
response.getDataErrors().get(0).toJson().toString(), false);
266+
}
267+
268+
@Test
269+
public void series2_phase2_Department_FindWithRoles() throws Exception{
270+
FindRequest findRequest = createRequest_FromResource(FindRequest.class, "./crud/find/department-find-single.json");
271+
findRequest.setClientId(new FakeClientIdentification("fakeUser", "admin"));
272+
273+
Response response = lightblueFactory.getMediator().find(findRequest);
274+
275+
assertNotNull(response);
276+
assertNoErrors(response);
277+
assertNoDataErrors(response);
278+
assertEquals(1, response.getMatchCount());
279+
280+
JsonNode entityData = response.getEntityData();
281+
assertNotNull(entityData);
282+
JSONAssert.assertEquals(
283+
"[{\"member#\":2,\"member\":[\"cn=John Doe," + BASEDB_USERS + "\",\"cn=Jane Doe," + BASEDB_USERS + "\"],\"cn\":\"Marketing\",\"description\":\"Department devoted to Marketing\"}]",
284+
entityData.toString(), true);
285+
}
286+
287+
@Test
288+
public void series2_phase2_Department_FindWithInsufficientRoles() throws Exception{
289+
FindRequest findRequest = createRequest_FromResource(FindRequest.class, "./crud/find/department-find-single.json");
290+
findRequest.setClientId(new FakeClientIdentification("fakeUser"));
291+
292+
Response response = lightblueFactory.getMediator().find(findRequest);
293+
294+
assertNotNull(response);
295+
assertEquals(1, response.getMatchCount());
296+
297+
assertNoErrors(response);
298+
assertNoDataErrors(response);
299+
300+
assertNotNull(response.getEntityData());
301+
JsonNode entityData = response.getEntityData();
302+
assertNotNull(entityData);
303+
304+
JSONAssert.assertEquals(
305+
"[{\"cn\":\"Marketing\",\"description\":\"Department devoted to Marketing\"}]",
306+
entityData.toString(), true);
184307
}
185308

186309
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"entity": "department",
3+
"entityVersion": "1.0.0",
4+
"projection": [
5+
{"field": "cn"},
6+
{"field": "member.*"},
7+
{"field": "member#"},
8+
{"field": "description"}
9+
],
10+
"query": {
11+
"field": "cn",
12+
"op": "$eq",
13+
"rvalue": "Marketing"
14+
}
15+
}

lightblue-ldap-integration-test/src/test/resources/crud/find/person-find-single.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,4 @@
1212
"op": "$eq",
1313
"rvalue": "john.doe"
1414
}
15-
}
15+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{
2+
"entity": "department",
3+
"entityVersion": "1.0.0",
4+
"projection": {
5+
"field": "dn"
6+
},
7+
"data": {
8+
"objectClass": ["groupofNames"],
9+
"cn": "#cn",
10+
"description": "#description",
11+
"member": [#members]
12+
}
13+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
{
2+
"entityInfo": {
3+
"name": "department",
4+
"datastore": {
5+
"backend":"ldap",
6+
"database": "${ldap.database}",
7+
"basedn": "${ldap.department.basedn}",
8+
"uniqueattr": "cn"
9+
}
10+
},
11+
"schema": {
12+
"name": "department",
13+
"version": {
14+
"value": "1.0.0",
15+
"changelog": "blahblah"
16+
},
17+
"status": {
18+
"value": "active"
19+
},
20+
"access" : {
21+
"insert": ["anyone"],
22+
"update": ["anyone"],
23+
"delete": ["anyone"],
24+
"find": ["anyone"]
25+
},
26+
"fields": {
27+
"cn": {"type": "string"},
28+
"member": {
29+
"type": "array",
30+
"items": {"type": "string"},
31+
"access": {
32+
"find": ["admin","manager"],
33+
"insert": ["admin"]
34+
}
35+
},
36+
"description": {"type": "string"}
37+
}
38+
}
39+
}

0 commit comments

Comments
 (0)