Skip to content

Commit 21a7fa6

Browse files
wb36499tb06904
andauthored
Gh-471: Add page explaining visibilities (#494)
* Adds formatting to existing v1 docs WIP * Fixes page link * Formatting edge examples & link * Minor tweaks * Fixes link to v1 docs * Fixes link url * Changes link & updates code example to generic addelement * Reworks serialiser & aggregator section --------- Co-authored-by: tb06904 <[email protected]>
1 parent bf0bc89 commit 21a7fa6

File tree

3 files changed

+268
-4
lines changed

3 files changed

+268
-4
lines changed

docs/administration-guide/gaffer-stores/accumulo-store.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ Gaffer can take advantage of Accumulo's built-in fine-grained security to ensure
146146

147147
If no "visibilityProperty" is specified then the column visibility is empty which means that anyone who has read access to the table can view it.
148148

149-
See [the visibility walkthrough](https://gchq.github.io/gaffer-doc/v1docs/getting-started/developer-guide/visibilities.html) in the [Dev Guide](https://gchq.github.io/gaffer-doc/v1docs/getting-started/developer-guide/contents.html) for an example of how properties can be aggregated over different visibilities at query time.
149+
See [the visibility walkthrough](../security/security-guide.md#using-visibilities-for-fine-grained-security) for an example of how properties can be aggregated over different visibilities at query time.
150150

151151
## Timestamp
152152

docs/administration-guide/security/security-guide.md

+266-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,267 @@
1-
!!! info "Work in Progress"
1+
# Security
2+
3+
## Using Visibilities for fine-grained security
4+
5+
Another one of Gaffer's key features is visibility filtering, fine grained data access and query execution controls.
6+
7+
[Javadoc](https://gchq.github.io/Gaffer/uk/gov/gchq/gaffer/commonutil/elementvisibilityutil/VisibilityEvaluator.html)
8+
9+
In this example we'll add a visibility property to our edges so that we can control access to them.
10+
11+
Let's assume that any road use information about junctions greater than 20 is private and only users that have the private data access authorization are allowed to view them.
12+
13+
We will use the same data as before but we need to modify the schema to add the new visibility property.
14+
15+
Here is the new elements schema:
16+
17+
```json
18+
{
19+
"edges": {
20+
"RoadUse": {
21+
"description": "A directed edge representing vehicles moving from junction A to junction B.",
22+
"source": "junction",
23+
"destination": "junction",
24+
"directed": "true",
25+
"properties": {
26+
"visibility": "visibility",
27+
"count": "count.long"
28+
}
29+
},
30+
"RoadHasJunction": {
31+
"description": "A directed edge from each road to all the junctions on that road.",
32+
"source": "road",
33+
"destination": "junction",
34+
"directed": "true"
35+
}
36+
},
37+
"visibilityProperty": "visibility"
38+
}
39+
```
40+
41+
We've added the new "visibility" property to the RoadUse edge. We have also told Gaffer that whenever it sees a property called 'visibility' that this is a special property and should be used for restricting a user's visibility of the data.
42+
43+
We've defined a new "visibility" type in our Types, which is a Java String and must be non-null in order for the related edge to be loaded into the Graph. Custom visibility serialiser and aggregator are not required, Gaffer will use the optimal methods by default. However, if custom serialisers and aggregators are required, they can be specificed as below.
44+
45+
```json
46+
{
47+
"types": {
48+
"junction": {
49+
"description": "A road junction represented by a String.",
50+
"class": "java.lang.String"
51+
},
52+
"road": {
53+
"description": "A road represented by a String.",
54+
"class": "java.lang.String"
55+
},
56+
"count.long": {
57+
"description": "A long count that must be greater than or equal to 0.",
58+
"class": "java.lang.Long",
59+
"validateFunctions": [
60+
{
61+
"class": "uk.gov.gchq.koryphe.impl.predicate.IsMoreThan",
62+
"orEqualTo": true,
63+
"value": {
64+
"java.lang.Long": 0
65+
}
66+
}
67+
],
68+
"aggregateFunction": {
69+
"class": "uk.gov.gchq.koryphe.impl.binaryoperator.Sum"
70+
}
71+
},
72+
"true": {
73+
"description": "A simple boolean that must always be true.",
74+
"class": "java.lang.Boolean",
75+
"validateFunctions": [
76+
{
77+
"class": "uk.gov.gchq.koryphe.impl.predicate.IsTrue"
78+
}
79+
]
80+
},
81+
"visibility": {
82+
"description": "A visibility string, either 'public' or 'private'. When a public and private visibility is aggregated together it will result in a private visibility.",
83+
"class": "java.lang.String",
84+
"validateFunctions": [
85+
{
86+
"class": "uk.gov.gchq.koryphe.impl.predicate.Exists"
87+
}
88+
],
89+
"serialiser": {
90+
"class": "uk.gov.gchq.gaffer.doc.dev.serialiser.VisibilitySerialiser"
91+
},
92+
"aggregateFunction": {
93+
"class": "uk.gov.gchq.gaffer.doc.dev.aggregator.VisibilityAggregator"
94+
}
95+
}
96+
}
97+
}
98+
99+
```
100+
### Adding elements with visibility
101+
102+
??? example "Adding new edges with visibilities"
103+
104+
=== "Java"
105+
106+
```java
107+
new AddElements.Builder()
108+
.input(new Edge.Builder()
109+
.group("RoadHasJunction")
110+
.source("1").dest("2").directed(true)
111+
.property("count", 1)
112+
.property("visibility", "private")
113+
.build(),
114+
new Edge.Builder()
115+
.group("RoadHasJunction")
116+
.source("1").dest("2").directed(true)
117+
.property("count", 2)
118+
.property("visibility", "public")
119+
.build())
120+
.build();
121+
```
122+
123+
=== "JSON"
124+
125+
``` JSON
126+
{
127+
"class" : "AddElements",
128+
"input" : [ {
129+
"class" : "Edge",
130+
"group" : "RoadHasJunction",
131+
"source" : "1",
132+
"destination" : "2",
133+
"directed" : true,
134+
"properties" : {
135+
"count" : 1,
136+
"visibility": "private"
137+
}
138+
},
139+
{
140+
"class" : "Edge",
141+
"group" : "RoadHasJunction",
142+
"source" : "1",
143+
"destination" : "2",
144+
"directed" : true,
145+
"properties" : {
146+
"count" : 2,
147+
"visibility": "public"
148+
}
149+
} ],
150+
"skipInvalidElements" : false,
151+
"validate" : true
152+
}
153+
```
154+
155+
=== "Python"
156+
157+
``` Python
158+
g.AddElements(
159+
input=[
160+
g.Edge(
161+
group="RoadHasJunction",
162+
properties={"count": 1, "visibility": "private"},
163+
source="1",
164+
destination="2",
165+
directed=True
166+
),
167+
g.Edge(
168+
group="RoadHasJunction",
169+
properties={"count": 2, "visibility": "public"},
170+
source="1",
171+
destination="2",
172+
directed=True
173+
)
174+
],
175+
skip_invalid_elements=False,
176+
validate=True
177+
)
178+
```
179+
180+
After creating a Graph and adding our edges to it we run a simple query to get back all RoadUse edges containing vertex "20"... and we get nothing back. This is because the user we ran the query as was not allowed to see edges with a visibility of public or private, so no edges were returned.
181+
182+
We can create a user that can see public edges only (and not private edges) and then run the query as this user.
183+
184+
```java
185+
final User publicUser = new User.Builder()
186+
.userId("publicUser")
187+
.dataAuth("public")
188+
.build();
189+
190+
final GetElements getPublicRelatedEdges = new GetElements.Builder()
191+
.input(new EntitySeed("10"), new EntitySeed("23"))
192+
.view(new View.Builder()
193+
.edge("RoadUse")
194+
.build())
195+
.build();
196+
197+
final CloseableIterable<? extends Element> publicResults = graph.execute(getPublicRelatedEdges, publicUser);
198+
199+
```
200+
201+
If we rerun the query with a public user, we just get back the public edges:
202+
203+
```java
204+
Edge[source=11,destination=10,directed=true,matchedVertex=DESTINATION,group=RoadUse,properties=Properties[visibility=<java.lang.String>public,count=<java.lang.Long>1]]
205+
Edge[source=10,destination=11,directed=true,matchedVertex=SOURCE,group=RoadUse,properties=Properties[visibility=<java.lang.String>public,count=<java.lang.Long>3]]
206+
```
207+
We can also create a user that can see private edges (and therefore public ones as well):
208+
209+
```java
210+
final User privateUser = new User.Builder()
211+
.userId("privateUser")
212+
.dataAuth("private")
213+
.build();
214+
215+
final GetElements getPrivateRelatedEdges = new GetElements.Builder()
216+
.input(new EntitySeed("10"), new EntitySeed("23"))
217+
.view(new View.Builder()
218+
.edge("RoadUse")
219+
.build())
220+
.build();
221+
222+
final CloseableIterable<? extends Element> privateResults = graph.execute(getPrivateRelatedEdges, privateUser);
223+
```
224+
225+
If we rerun the query as the private user, we get back all of the edges:
226+
227+
```java
228+
Edge[source=23,destination=24,directed=true,matchedVertex=SOURCE,group=RoadUse,properties=Properties[visibility=<java.lang.String>private,count=<java.lang.Long>2]]
229+
```
230+
231+
Here we performed a query with just 2 seeds. You can provide as many seeds here as you like and the Gaffer store will handle it for you, batching them up if required.
232+
233+
The visibility property as defined by the visibilityProperty field in the Schema is special case of a groupBy property.
234+
235+
- When ingest aggregation is carried out the visibilityProperty is treated as groupBy property.
236+
- When query aggregation is carried out the visibilityProperty is no longer treated as a groupBy property.
237+
238+
To further demonstrate this, here is another example:
239+
240+
Add the following Edges:
241+
242+
```
243+
1 -> 2 count = 1, visibility = "public"
244+
1 -> 2 count = 2, visibility = "public"
245+
1 -> 2 count = 10, visibility = "private"
246+
1 -> 2 count = 20, visibility = "private"
247+
```
248+
249+
These are persisted keeping the Edges with different visibilities separate, you can see the counts have been aggregated as they are not a groupBy property:
250+
251+
```
252+
1 -> 2 count = 3, visibility = "public"
253+
1 -> 2 count = 30, visibility = "private"
254+
```
255+
256+
Then if a user with just "public" access to the system does a query they will just get back:
257+
258+
```
259+
1 -> 2 count = 3, visibility = "public"
260+
```
261+
262+
A user with "private" access, who by definition can also see "public" data, will get back both edges aggregated together:
263+
264+
```
265+
1 -> 2 count = 33, visibility = "private"
266+
```
2267

3-
This page is under construction.

docs/reference/operations-guide/core.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -4528,7 +4528,7 @@ Gets the traits of the current store. [Javadoc](https://gchq.github.io/Gaffer/uk
45284528

45294529
Deletes all retained data including deleting the graph. [Javadoc](https://gchq.github.io/Gaffer/uk/gov/gchq/gaffer/store/operation/DeleteAllData.html)
45304530

4531-
To use this operation, it must be enabled via an [operations declarations JSON](../../administration-guide/gaffer-config/config.md#operationsdeclarationsjson).
4531+
To use this operation, it must be enabled via an [operations declarations JSON](../../administration-guide/gaffer-config/config.md#operations-declarations-json).
45324532

45334533
Note this operation does not return any response.
45344534

0 commit comments

Comments
 (0)