-
Notifications
You must be signed in to change notification settings - Fork 32
Expand file tree
/
Copy pathBasicAuthorizationEngine.java
More file actions
152 lines (133 loc) · 6.24 KB
/
BasicAuthorizationEngine.java
File metadata and controls
152 lines (133 loc) · 6.24 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
/*
* Copyright 2022-2023 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.cedarpolicy;
import static com.cedarpolicy.CedarJson.objectReader;
import static com.cedarpolicy.CedarJson.objectWriter;
import java.io.IOException;
import com.cedarpolicy.model.AuthorizationResponse;
import com.cedarpolicy.model.ValidationRequest;
import com.cedarpolicy.model.ValidationResponse;
import com.cedarpolicy.model.exception.AuthException;
import com.cedarpolicy.model.exception.BadRequestException;
import com.cedarpolicy.model.exception.InternalException;
import com.cedarpolicy.model.slice.Slice;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/** An authorization engine that is compiled in process. Communicated with via JNI. */
public final class BasicAuthorizationEngine implements AuthorizationEngine {
private static final Logger LOG = LoggerFactory.getLogger(BasicAuthorizationEngine.class);
static {
System.load(System.getenv("CEDAR_JAVA_FFI_LIB"));
}
/** Construct a basic authorization engine. */
public BasicAuthorizationEngine() {}
@Override
public AuthorizationResponse isAuthorized(com.cedarpolicy.model.AuthorizationRequest q, Slice slice)
throws AuthException {
LOG.trace("Making an isAuthorized request:\n{}\nwith slice\n{}", q, slice);
final AuthorizationRequest request = new AuthorizationRequest(q, slice);
return call("AuthorizationOperation", AuthorizationResponse.class, request);
}
@Override
public ValidationResponse validate(ValidationRequest q) throws AuthException {
LOG.trace("Making a validate request:\n{}", q);
return call("ValidateOperation", ValidationResponse.class, q);
}
private static <REQ, RESP> RESP call(String operation, Class<RESP> responseClass, REQ request)
throws AuthException {
try {
final String cedarJNIVersion = getCedarJNIVersion();
if (!cedarJNIVersion.equals(AuthorizationEngine.getCedarLangVersion())) {
throw new AuthException(
"Error, Java Cedar Language version is "
+ AuthorizationEngine.getCedarLangVersion()
+ " but JNI Cedar Language version is "
+ cedarJNIVersion);
}
final String fullRequest = objectWriter().writeValueAsString(request);
LOG.debug(
"Making a request ({}, {}) of length {} through the JNI interface:",
operation,
fullRequest.length());
LOG.trace("The request:\n{}", fullRequest);
final String response = callCedarJNI(operation, fullRequest);
LOG.trace("Received response of length {}:\n{}", response.length(), response);
final JsonNode responseNode = objectReader().readTree(response);
boolean wasSuccessful = responseNode.path("success").asBoolean(false);
if (wasSuccessful) {
final String resultJson = responseNode.path("result").textValue();
return objectReader().readValue(resultJson, responseClass);
} else {
final ErrorResponse error = objectReader().forType(ErrorResponse.class).readValue(responseNode);
if (error.isInternal) {
throw new InternalException(error.errors);
} else {
throw new BadRequestException(error.errors);
}
}
} catch (JsonProcessingException e) {
throw new AuthException("JSON Serialization Error", e);
} catch (IllegalArgumentException e) {
throw new AuthException("Authorization error caused by illegal argument exception.", e);
} catch (IOException e) {
throw new AuthException("JSON Deserialization Error", e);
}
}
private static final class AuthorizationRequest extends com.cedarpolicy.model.AuthorizationRequest {
@JsonProperty public final Slice slice;
AuthorizationRequest(com.cedarpolicy.model.AuthorizationRequest request, Slice slice) {
super(
request.principalEUID,
request.actionEUID,
request.resourceEUID,
request.context,
request.schema,
request.enable_request_validation);
this.slice = slice;
}
}
private static final class ErrorResponse {
public final boolean success, isInternal;
public final String[] errors;
@JsonCreator
ErrorResponse(
@JsonProperty("success") boolean success,
@JsonProperty("isInternal") boolean isInternal,
@JsonProperty("errors") String[] errors) {
this.success = success;
this.isInternal = isInternal;
this.errors = errors;
}
}
/**
* Call out to the Rust implementation.
*
* @param call Call type ("AuthorizationOperation" or "ValidateOperation").
* @param input Request input in JSON format as a String
* @return The response (permit / deny for authorization, valid / invalid for validation)
*/
private static native String callCedarJNI(String call, String input);
/**
* Get the Cedar language major version supported by the JNI (e.g., "1.2")
*
* @return The Cedar language version supported by the JNI
*/
private static native String getCedarJNIVersion();
}