-
Notifications
You must be signed in to change notification settings - Fork 7
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add OpaS3SecurityFacade #149
Conversation
...-proxy/src/main/java/io/trino/aws/proxy/server/security/opa/OpaS3SecurityFacadeProvider.java
Outdated
Show resolved
Hide resolved
trino-aws-proxy/src/test/java/io/trino/aws/proxy/server/TestOpaSecurity.java
Outdated
Show resolved
Hide resolved
trino-aws-proxy/src/test/java/io/trino/aws/proxy/server/TestOpaSecurity.java
Outdated
Show resolved
Hide resolved
07fb41e
to
472d44a
Compare
...-proxy/src/main/java/io/trino/aws/proxy/server/security/opa/OpaS3SecurityFacadeProvider.java
Outdated
Show resolved
Hide resolved
trino-aws-proxy/src/test/java/io/trino/aws/proxy/server/TestOpaSecurity.java
Outdated
Show resolved
Hide resolved
472d44a
to
ff95d03
Compare
{ | ||
record OpaRequestWrapper(OpaRequest opaRequest) implements OpaRequestAdapter | ||
{ | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
add requireNonNull
|
||
record SecurityResponseWrapper(SecurityResponse securityResponse) implements OpaRequestAdapter | ||
{ | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
add requireNonNull
|
||
public sealed interface OpaRequestAdapter | ||
{ | ||
record OpaRequestWrapper(OpaRequest opaRequest) implements OpaRequestAdapter |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Apply Trino style - implements
should be indented on next line
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm -1 on this change. The goal, as I understand it, is to be able to short-circuit the OPA request and return a Security response without querying the OPA server.
IMO a better way of doing this is adding an OPA query mechanism that is separate from the OPA mapping. If users want to short-circuit, they can inject a query adaptor that does that.
E.g.
public interface OpaClient
{
SecurityResponse requestSecurityResponse(OpaRequest request);
}
The default implementation would be the body of OpaS3SecurityFacadeProvider.securityFacadeForRequest()
.
The OpaModule would optionally bind a default to the default OpaClient which would look like this:
public class DefaultOpaClient
implements OpaClient
{
private static final JsonCodec<Map<String, Object>> CODEC = mapJsonCodec(String.class, Object.class);
private final HttpClient httpClient;
@Inject
public DefaultOpaClient(@ForOpa HttpClient httpClient)
{
this.httpClient = requireNonNull(httpClient, "httpClient is null");
}
@Override
public SecurityResponse requestSecurityResponse(OpaRequest opaRequest)
{
Map<String, Object> inputDocument = toInputDocument(opaRequest.document());
Request.Builder builder = preparePost()
.setUri(opaRequest.opaServerUri())
.addHeader(CONTENT_TYPE, APPLICATION_JSON_TYPE.getType())
.setBodyGenerator(jsonBodyGenerator(CODEC, inputDocument));
opaRequest.additionalHeaders().forEach((name, values) -> values.forEach(value -> builder.addHeader(name, value)));
Map<String, Object> responseDocument = httpClient.execute(builder.build(), createJsonResponseHandler(CODEC));
return toSecurityResponse(responseDocument);
}
private static Map<String, Object> toInputDocument(Map<String, Object> document)
{
/*
Default formats standard input:
{
"input": {
... nested document ...
}
}
*/
return ImmutableMap.of("input", document);
}
private static SecurityResponse toSecurityResponse(Map<String, Object> responseDocument)
{
/*
Default handles standard response:
{
"result": true/false
}
*/
return extractBoolean(responseDocument, "result")
.map(allowed -> allowed ? SUCCESS : FAILURE)
.orElse(FAILURE);
}
private static Optional<Boolean> extractBoolean(Map<?, ?> map, String key)
{
return switch (map.get(key)) {
case Boolean b -> Optional.of(b);
case null, default -> Optional.empty();
};
}
}
You'll need to add keyInBucket
to OpaRequest
re @Randgalt I think the mapper.toSecurityResponse(opaClient.requestSecurityResponse(mapper.toOparequest(...))) In this case I think its better off to just implement a custom This approach doesn't quite provide the short-circuit functionality. The mapper would have to return some special |
|
||
public sealed interface OpaRequestAdapter | ||
{ | ||
record OpaRequestWrapper(OpaRequest opaRequest) implements OpaRequestAdapter |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we make the constructors of OpaRequestAdapter
, OpaRequestWrapper
and SecurityResponseWrapper
private/protected and provide 2 static functions in OpaRequestAdapter
: ofOpaRequest
and ofSecurityResponse
?
|
||
import io.trino.aws.proxy.spi.security.SecurityResponse; | ||
|
||
public sealed interface OpaRequestAdapter |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
WDYT of OpaRequestOrSecurityResponse
as the interface name? A bit wordy but very descriptive
40090db
to
50e10a8
Compare
...-proxy/src/main/java/io/trino/aws/proxy/server/security/opa/OpaS3SecurityFacadeProvider.java
Outdated
Show resolved
Hide resolved
trino-aws-proxy/src/test/java/io/trino/aws/proxy/server/TestOpaSecurity.java
Outdated
Show resolved
Hide resolved
50e10a8
to
f8120a7
Compare
Related to #148