Skip to content

Commit 114262a

Browse files
committed
forbidden exception handling + owner of share authorized
1 parent b43a2ff commit 114262a

File tree

9 files changed

+110
-56
lines changed

9 files changed

+110
-56
lines changed

server/app/src/main/java/io/whitefox/api/deltasharing/server/DeltaSharesApiImpl.java

Lines changed: 35 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -43,12 +43,10 @@ public DeltaSharesApiImpl(
4343
@Override
4444
public Response getShare(String share) {
4545
return wrapExceptions(
46-
() -> optionalToNotFound(
47-
shareService.getShare(share),
48-
foundShare -> shareToForbidden(foundShare, s -> {
49-
var resultShare = new Share().name(s.name()).id(s.id());
50-
return Response.ok(resultShare).build();
51-
})),
46+
() -> optionalToNotFound(shareService.getShare(share), s -> {
47+
var resultShare = new Share().name(s.name()).id(s.id());
48+
return Response.ok(resultShare).build();
49+
}),
5250
exceptionToResponse);
5351
}
5452

@@ -73,28 +71,26 @@ public Response getTableMetadata(
7371
String startingTimestampStr,
7472
String deltaSharingCapabilities) {
7573
return wrapExceptions(
76-
() -> optionalToNotFound(
77-
shareService.getShare(share),
78-
foundShare -> shareToForbidden(foundShare, s -> {
79-
var startingTimestamp = parseTimestamp(startingTimestampStr);
80-
return optionalToNotFound(
81-
deltaSharesService.getTableMetadata(
74+
() -> {
75+
var startingTimestamp = parseTimestamp(startingTimestampStr);
76+
return optionalToNotFound(
77+
deltaSharesService.getTableMetadata(
78+
share, schema, table, startingTimestamp, getRequestPrincipal()),
79+
m -> optionalToNotFound(
80+
deltaSharesService.getTableVersion(
8281
share, schema, table, startingTimestamp, getRequestPrincipal()),
83-
m -> optionalToNotFound(
84-
deltaSharesService.getTableVersion(
85-
share, schema, table, startingTimestamp, getRequestPrincipal()),
86-
v -> Response.ok(
87-
tableResponseSerializer.serialize(
88-
DeltaMappers.toTableResponseMetadata(m)),
89-
ndjsonMediaType)
90-
.status(Response.Status.OK.getStatusCode())
91-
.header(DELTA_TABLE_VERSION_HEADER, String.valueOf(v))
92-
.header(
93-
DELTA_SHARE_CAPABILITIES_HEADER,
94-
getResponseFormatHeader(
95-
DeltaMappers.toHeaderCapabilitiesMap(deltaSharingCapabilities)))
96-
.build()));
97-
})),
82+
v -> Response.ok(
83+
tableResponseSerializer.serialize(
84+
DeltaMappers.toTableResponseMetadata(m)),
85+
ndjsonMediaType)
86+
.status(Response.Status.OK.getStatusCode())
87+
.header(DELTA_TABLE_VERSION_HEADER, String.valueOf(v))
88+
.header(
89+
DELTA_SHARE_CAPABILITIES_HEADER,
90+
getResponseFormatHeader(
91+
DeltaMappers.toHeaderCapabilitiesMap(deltaSharingCapabilities)))
92+
.build()));
93+
},
9894
exceptionToResponse);
9995
}
10096

@@ -116,24 +112,18 @@ share, schema, table, startingTimestamp, getRequestPrincipal()),
116112
public Response listALLTables(String share, Integer maxResults, String pageToken) {
117113
return wrapExceptions(
118114
() -> optionalToNotFound(
119-
shareService.getShare(share),
120-
foundShare -> shareToForbidden(
121-
foundShare,
122-
s -> optionalToNotFound(
123-
deltaSharesService.listTablesOfShare(
124-
share,
125-
parseToken(pageToken),
126-
Optional.ofNullable(maxResults),
127-
getRequestPrincipal()),
128-
c -> Response.ok(c.getToken()
129-
.map(
130-
t -> new ListTablesResponse()
131-
.items(mapList(c.getContent(), DeltaMappers::table2api))
132-
.nextPageToken(tokenEncoder.encodePageToken(t)))
133-
.orElse(
134-
new ListTablesResponse()
135-
.items(mapList(c.getContent(), DeltaMappers::table2api))))
136-
.build()))),
115+
deltaSharesService.listTablesOfShare(
116+
share,
117+
parseToken(pageToken),
118+
Optional.ofNullable(maxResults),
119+
getRequestPrincipal()),
120+
c -> Response.ok(c.getToken()
121+
.map(t -> new ListTablesResponse()
122+
.items(mapList(c.getContent(), DeltaMappers::table2api))
123+
.nextPageToken(tokenEncoder.encodePageToken(t)))
124+
.orElse(new ListTablesResponse()
125+
.items(mapList(c.getContent(), DeltaMappers::table2api))))
126+
.build()),
137127
exceptionToResponse);
138128
}
139129

server/app/src/main/java/io/whitefox/api/server/ApiUtils.java

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@
33
import io.quarkus.runtime.util.ExceptionUtil;
44
import io.whitefox.api.deltasharing.model.v1.generated.CommonErrorResponse;
55
import io.whitefox.core.Principal;
6-
import io.whitefox.core.Share;
76
import io.whitefox.core.services.DeltaSharedTable;
87
import io.whitefox.core.services.exceptions.AlreadyExists;
98
import io.whitefox.core.services.exceptions.NotFound;
9+
import jakarta.ws.rs.ForbiddenException;
1010
import jakarta.ws.rs.core.Response;
1111
import java.sql.Timestamp;
1212
import java.time.OffsetDateTime;
@@ -44,6 +44,12 @@ public interface ApiUtils extends DeltaHeaders {
4444
.errorCode("BAD REQUEST - timestamp provided is not formatted correctly")
4545
.message(ExceptionUtil.generateStackTrace(t)))
4646
.build();
47+
} else if (t instanceof ForbiddenException) {
48+
return Response.status(Response.Status.FORBIDDEN)
49+
.entity(new CommonErrorResponse()
50+
.errorCode("FORBIDDEN ACCESS")
51+
.message(ExceptionUtil.generateStackTrace(t)))
52+
.build();
4753
} else {
4854
return Response.status(Response.Status.BAD_GATEWAY)
4955
.entity(new CommonErrorResponse()
@@ -67,13 +73,14 @@ default Response notFoundResponse() {
6773
.build();
6874
}
6975

70-
default <T> Response optionalToNotFound(Optional<T> opt, Function<T, Response> fn) {
71-
return opt.map(fn).orElse(notFoundResponse());
76+
default Response forbiddenResponse() {
77+
return Response.status(Response.Status.FORBIDDEN)
78+
.entity(new CommonErrorResponse().errorCode("2").message("UNAUTHORIZED ACCESS"))
79+
.build();
7280
}
7381

74-
default Response shareToForbidden(Share value, Function<Share, Response> fn) {
75-
if (value.recipients().contains(getRequestPrincipal())) return fn.apply(value);
76-
else return Response.status(Response.Status.FORBIDDEN).build();
82+
default <T> Response optionalToNotFound(Optional<T> opt, Function<T, Response> fn) {
83+
return opt.map(fn).orElse(notFoundResponse());
7784
}
7885

7986
default String getResponseFormatHeader(Map<String, String> deltaSharingCapabilities) {

server/app/src/test/java/io/whitefox/api/deltasharing/SampleTables.java

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,23 @@ public static StorageManager createStorageManager() {
6666
new SharedTable("icebergtable2", "default", "name", icebergtable2)),
6767
"name")),
6868
testPrincipal,
69-
0L)));
69+
0L),
70+
new io.whitefox.core.Share(
71+
"noauthShare",
72+
"key",
73+
Map.of(
74+
"default",
75+
new io.whitefox.core.Schema(
76+
"default",
77+
List.of(
78+
new SharedTable("table1", "default", "name", deltaTable1),
79+
new SharedTable(
80+
"table-with-history", "default", "name", deltaTableWithHistory1),
81+
new SharedTable("icebergtable1", "default", "name", icebergtable1),
82+
new SharedTable("icebergtable2", "default", "name", icebergtable2)),
83+
"name")),
84+
new Principal("Mr. White"),
85+
0L)));
7086
}
7187

7288
public static final MetadataObject deltaTable1Metadata = new MetadataObject()

server/app/src/test/java/io/whitefox/api/deltasharing/server/DeltaSharesApiImplTest.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,16 @@ public void listNotFoundSchemas() {
104104
.body("message", is("NOT FOUND"));
105105
}
106106

107+
@Test
108+
public void listSchemasNoAuth() {
109+
given()
110+
.when()
111+
.filter(deltaFilter)
112+
.get("delta-api/v1/shares/{share}/schemas", "noauthShare")
113+
.then()
114+
.statusCode(403);
115+
}
116+
107117
@Test
108118
public void listSchemas() {
109119
given()
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1-
quarkus.http.test-port=8080
1+
quarkus.http.test-port=8080
2+
quarkus.test.arg-line=-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=*:5005

server/core/src/main/java/io/whitefox/core/Share.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ public Share(
5050
id,
5151
schemas,
5252
Optional.empty(),
53-
Set.of(createPrincipal),
53+
Set.of(),
5454
createTime,
5555
createPrincipal,
5656
createTime,

server/core/src/main/java/io/whitefox/core/WhitefoxAuthorization.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ class WhitefoxSimpleAuthorization implements WhitefoxAuthorization {
1313

1414
@Override
1515
public Boolean authorize(Share share, Principal principal) {
16-
return share.recipients().contains(principal);
16+
return share.recipients().contains(principal) || share.owner().equals(principal);
1717
}
1818
}
1919
}

server/core/src/main/java/io/whitefox/core/services/DeltaSharesServiceImpl.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,8 @@ public ContentAndToken<List<Share>> listShares(
6969
Optional<ContentAndToken.Token> optionalToken =
7070
end < pageContent.size() ? Optional.of(new ContentAndToken.Token(end)) : Optional.empty();
7171
var content = pageContent.result().stream()
72-
.filter(s -> s.recipients().contains(currentPrincipal))
72+
.filter(
73+
s -> s.recipients().contains(currentPrincipal) || s.owner().equals(currentPrincipal))
7374
.collect(Collectors.toList());
7475
return optionalToken
7576
.map(t -> ContentAndToken.of(content, t))

server/core/src/test/java/io/whitefox/core/services/DeltaShareServiceTest.java

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import io.whitefox.core.services.exceptions.TableNotFound;
1313
import io.whitefox.persistence.StorageManager;
1414
import io.whitefox.persistence.memory.InMemoryStorageManager;
15+
import jakarta.ws.rs.ForbiddenException;
1516
import java.util.Collections;
1617
import java.util.List;
1718
import java.util.Map;
@@ -30,6 +31,7 @@ public class DeltaShareServiceTest {
3031
WhitefoxAuthorization whitefoxAuthorization = new WhitefoxSimpleAuthorization();
3132

3233
private static final Principal testPrincipal = new Principal("Mr. Fox");
34+
private static final Principal badPrincipal = new Principal("Mr. White");
3335

3436
private static Share createShare(String name, String key, Map<String, Schema> schemas) {
3537
return new Share(name, key, schemas, testPrincipal, 0L);
@@ -51,6 +53,21 @@ public void listShares() {
5153
Assertions.assertTrue(sharesWithNextToken.getToken().isEmpty());
5254
}
5355

56+
@Test
57+
public void listSharesUnauthorized() {
58+
var shares = List.of(new Share("name", "key", Collections.emptyMap(), badPrincipal, 0L));
59+
StorageManager storageManager = new InMemoryStorageManager(shares);
60+
DeltaSharesService deltaSharesService = new DeltaSharesServiceImpl(
61+
storageManager,
62+
defaultMaxResults,
63+
tableLoaderFactory,
64+
fileSignerFactory,
65+
whitefoxAuthorization);
66+
var sharesWithNextToken =
67+
deltaSharesService.listShares(Optional.empty(), Optional.of(30), testPrincipal);
68+
Assertions.assertEquals(0, sharesWithNextToken.getContent().size());
69+
}
70+
5471
@Test
5572
public void listSharesWithToken() {
5673
var shares = List.of(createShare("name", "key", Collections.emptyMap()));
@@ -80,6 +97,18 @@ public void listSchemasOfEmptyShare() {
8097
Assertions.assertTrue(resultSchemas.get().getToken().isEmpty());
8198
}
8299

100+
@Test
101+
public void listSchemasNoAuth() {
102+
var shares = List.of(new Share("name", "key", Collections.emptyMap(), badPrincipal, 0L));
103+
StorageManager storageManager = new InMemoryStorageManager(shares);
104+
DeltaSharesService deltaSharesService = new DeltaSharesServiceImpl(
105+
storageManager, 100, tableLoaderFactory, fileSignerFactory, whitefoxAuthorization);
106+
assertThrows(
107+
ForbiddenException.class,
108+
() -> deltaSharesService.listSchemas(
109+
"name", Optional.empty(), Optional.empty(), testPrincipal));
110+
}
111+
83112
@Test
84113
public void listSchemas() {
85114
var shares = List.of(createShare(

0 commit comments

Comments
 (0)