cedar_policy 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Cargo.lock +45 -25
- data/README.md +18 -17
- data/ext/cedar_policy/Cargo.toml +3 -1
- data/ext/cedar_policy/src/authorizer.rs +14 -7
- data/ext/cedar_policy/src/context.rs +51 -0
- data/ext/cedar_policy/src/decision.rs +25 -14
- data/ext/cedar_policy/src/entities.rs +38 -24
- data/ext/cedar_policy/src/entity_uid.rs +51 -34
- data/ext/cedar_policy/src/lib.rs +5 -5
- data/ext/cedar_policy/src/policy_set.rs +20 -12
- data/ext/cedar_policy/src/request.rs +26 -21
- data/ext/cedar_policy/src/response.rs +1 -1
- data/lib/cedar_policy/context.rb +14 -0
- data/lib/cedar_policy/entities.rb +14 -0
- data/lib/cedar_policy/entity.rb +32 -0
- data/lib/cedar_policy/entity_uid.rb +31 -0
- data/lib/cedar_policy/version.rb +1 -1
- data/lib/cedar_policy.rb +21 -1
- metadata +7 -3
- data/ext/cedar_policy/src/entity.rs +0 -70
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3d74502a574ecb798f539deef9534d297f8f60802fc1614a2ba61a0b04c381e8
|
4
|
+
data.tar.gz: 052ea0f3383e332bcd94931ff7f5c57f45aa2ffbd126e3e8628574e20dd39d98
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1a1311adf918c900f7baac517ed7942377cbe8ded2e44c7228926d1e84db87a10bf81b474cc68d9555f4b4db5a754ab7e29c41df508c06e3878f2daab3126adb
|
7
|
+
data.tar.gz: 7c038820cfb7c60d0730ab7d8d10f43acce0afcf10db84e97b3c4e76c8f49b6d469cfdf66c37edbd4531bc8ace9ffd66deaa146d9afa5550b87894be2263875a
|
data/Cargo.lock
CHANGED
@@ -170,7 +170,9 @@ name = "cedar_policy"
|
|
170
170
|
version = "0.1.0"
|
171
171
|
dependencies = [
|
172
172
|
"cedar-policy",
|
173
|
+
"cedar-policy-core",
|
173
174
|
"magnus",
|
175
|
+
"serde_magnus",
|
174
176
|
]
|
175
177
|
|
176
178
|
[[package]]
|
@@ -400,9 +402,9 @@ dependencies = [
|
|
400
402
|
|
401
403
|
[[package]]
|
402
404
|
name = "indexmap"
|
403
|
-
version = "2.
|
405
|
+
version = "2.4.0"
|
404
406
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
405
|
-
checksum = "
|
407
|
+
checksum = "93ead53efc7ea8ed3cfb0c79fc8023fbb782a5432b52830b6518941cebe6505c"
|
406
408
|
dependencies = [
|
407
409
|
"equivalent",
|
408
410
|
"hashbrown 0.14.5",
|
@@ -435,9 +437,9 @@ checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
|
|
435
437
|
|
436
438
|
[[package]]
|
437
439
|
name = "js-sys"
|
438
|
-
version = "0.3.
|
440
|
+
version = "0.3.70"
|
439
441
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
440
|
-
checksum = "
|
442
|
+
checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a"
|
441
443
|
dependencies = [
|
442
444
|
"wasm-bindgen",
|
443
445
|
]
|
@@ -529,9 +531,9 @@ checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
|
|
529
531
|
|
530
532
|
[[package]]
|
531
533
|
name = "magnus"
|
532
|
-
version = "0.
|
534
|
+
version = "0.6.4"
|
533
535
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
534
|
-
checksum = "
|
536
|
+
checksum = "b1597ef40aa8c36be098249e82c9a20cf7199278ac1c1a1a995eeead6a184479"
|
535
537
|
dependencies = [
|
536
538
|
"magnus-macros",
|
537
539
|
"rb-sys",
|
@@ -659,7 +661,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
659
661
|
checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db"
|
660
662
|
dependencies = [
|
661
663
|
"fixedbitset",
|
662
|
-
"indexmap 2.
|
664
|
+
"indexmap 2.4.0",
|
663
665
|
]
|
664
666
|
|
665
667
|
[[package]]
|
@@ -865,18 +867,18 @@ checksum = "a3f0bf26fd526d2a95683cd0f87bf103b8539e2ca1ef48ce002d67aad59aa0b4"
|
|
865
867
|
|
866
868
|
[[package]]
|
867
869
|
name = "serde"
|
868
|
-
version = "1.0.
|
870
|
+
version = "1.0.207"
|
869
871
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
870
|
-
checksum = "
|
872
|
+
checksum = "5665e14a49a4ea1b91029ba7d3bca9f299e1f7cfa194388ccc20f14743e784f2"
|
871
873
|
dependencies = [
|
872
874
|
"serde_derive",
|
873
875
|
]
|
874
876
|
|
875
877
|
[[package]]
|
876
878
|
name = "serde_derive"
|
877
|
-
version = "1.0.
|
879
|
+
version = "1.0.207"
|
878
880
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
879
|
-
checksum = "
|
881
|
+
checksum = "6aea2634c86b0e8ef2cfdc0c340baede54ec27b1e46febd7f80dffb2aa44a00e"
|
880
882
|
dependencies = [
|
881
883
|
"proc-macro2",
|
882
884
|
"quote",
|
@@ -885,17 +887,28 @@ dependencies = [
|
|
885
887
|
|
886
888
|
[[package]]
|
887
889
|
name = "serde_json"
|
888
|
-
version = "1.0.
|
890
|
+
version = "1.0.124"
|
889
891
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
890
|
-
checksum = "
|
892
|
+
checksum = "66ad62847a56b3dba58cc891acd13884b9c61138d330c0d7b6181713d4fce38d"
|
891
893
|
dependencies = [
|
892
|
-
"indexmap 2.
|
894
|
+
"indexmap 2.4.0",
|
893
895
|
"itoa",
|
894
896
|
"memchr",
|
895
897
|
"ryu",
|
896
898
|
"serde",
|
897
899
|
]
|
898
900
|
|
901
|
+
[[package]]
|
902
|
+
name = "serde_magnus"
|
903
|
+
version = "0.8.1"
|
904
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
905
|
+
checksum = "76c20da583b5e1016e9199ef5f3260f7a8d1b253307d232600f6b12737262dbd"
|
906
|
+
dependencies = [
|
907
|
+
"magnus",
|
908
|
+
"serde",
|
909
|
+
"tap",
|
910
|
+
]
|
911
|
+
|
899
912
|
[[package]]
|
900
913
|
name = "serde_with"
|
901
914
|
version = "3.9.0"
|
@@ -906,7 +919,7 @@ dependencies = [
|
|
906
919
|
"chrono",
|
907
920
|
"hex",
|
908
921
|
"indexmap 1.9.3",
|
909
|
-
"indexmap 2.
|
922
|
+
"indexmap 2.4.0",
|
910
923
|
"serde",
|
911
924
|
"serde_derive",
|
912
925
|
"serde_json",
|
@@ -1002,6 +1015,12 @@ dependencies = [
|
|
1002
1015
|
"unicode-ident",
|
1003
1016
|
]
|
1004
1017
|
|
1018
|
+
[[package]]
|
1019
|
+
name = "tap"
|
1020
|
+
version = "1.0.1"
|
1021
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
1022
|
+
checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
|
1023
|
+
|
1005
1024
|
[[package]]
|
1006
1025
|
name = "term"
|
1007
1026
|
version = "0.7.0"
|
@@ -1149,19 +1168,20 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
|
1149
1168
|
|
1150
1169
|
[[package]]
|
1151
1170
|
name = "wasm-bindgen"
|
1152
|
-
version = "0.2.
|
1171
|
+
version = "0.2.93"
|
1153
1172
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
1154
|
-
checksum = "
|
1173
|
+
checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5"
|
1155
1174
|
dependencies = [
|
1156
1175
|
"cfg-if",
|
1176
|
+
"once_cell",
|
1157
1177
|
"wasm-bindgen-macro",
|
1158
1178
|
]
|
1159
1179
|
|
1160
1180
|
[[package]]
|
1161
1181
|
name = "wasm-bindgen-backend"
|
1162
|
-
version = "0.2.
|
1182
|
+
version = "0.2.93"
|
1163
1183
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
1164
|
-
checksum = "
|
1184
|
+
checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b"
|
1165
1185
|
dependencies = [
|
1166
1186
|
"bumpalo",
|
1167
1187
|
"log",
|
@@ -1174,9 +1194,9 @@ dependencies = [
|
|
1174
1194
|
|
1175
1195
|
[[package]]
|
1176
1196
|
name = "wasm-bindgen-macro"
|
1177
|
-
version = "0.2.
|
1197
|
+
version = "0.2.93"
|
1178
1198
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
1179
|
-
checksum = "
|
1199
|
+
checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf"
|
1180
1200
|
dependencies = [
|
1181
1201
|
"quote",
|
1182
1202
|
"wasm-bindgen-macro-support",
|
@@ -1184,9 +1204,9 @@ dependencies = [
|
|
1184
1204
|
|
1185
1205
|
[[package]]
|
1186
1206
|
name = "wasm-bindgen-macro-support"
|
1187
|
-
version = "0.2.
|
1207
|
+
version = "0.2.93"
|
1188
1208
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
1189
|
-
checksum = "
|
1209
|
+
checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836"
|
1190
1210
|
dependencies = [
|
1191
1211
|
"proc-macro2",
|
1192
1212
|
"quote",
|
@@ -1197,9 +1217,9 @@ dependencies = [
|
|
1197
1217
|
|
1198
1218
|
[[package]]
|
1199
1219
|
name = "wasm-bindgen-shared"
|
1200
|
-
version = "0.2.
|
1220
|
+
version = "0.2.93"
|
1201
1221
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
1202
|
-
checksum = "
|
1222
|
+
checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484"
|
1203
1223
|
|
1204
1224
|
[[package]]
|
1205
1225
|
name = "winapi"
|
data/README.md
CHANGED
@@ -26,34 +26,35 @@ policy = <<~POLICY
|
|
26
26
|
resource
|
27
27
|
);
|
28
28
|
POLICY
|
29
|
-
policy_set = CedarPolicy::PolicySet.
|
29
|
+
policy_set = CedarPolicy::PolicySet.new(policy)
|
30
30
|
|
31
|
-
principal = CedarPolicy::EntityUid.new("
|
31
|
+
principal = CedarPolicy::EntityUid.new("User", "1")
|
32
32
|
action = CedarPolicy::EntityUid.new("Action", "view")
|
33
33
|
resource = CedarPolicy::EntityUid.new("Image", "1")
|
34
|
+
ctx = CedarPolicy::Context.new
|
34
35
|
|
35
|
-
request = CedarPolicy::Request.new(principal, action, resource)
|
36
|
+
request = CedarPolicy::Request.new(principal, action, resource, ctx)
|
36
37
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
}
|
44
|
-
]
|
45
|
-
JSON
|
46
|
-
entities = CedarPolicy::Entities.from_json(entities_json)
|
38
|
+
entities = CedarPolicy::Entities.new([
|
39
|
+
CedarPolicy::Entity.new(
|
40
|
+
CedarPolicy::EntityUid.new("User", "1"),
|
41
|
+
{ role: "admin" }
|
42
|
+
)
|
43
|
+
])
|
47
44
|
|
48
45
|
authorizer = CedarPolicy::Authorizer.new
|
49
|
-
|
50
|
-
authorized = authorizer.authorize?(request, policy_set, entities) # => true
|
46
|
+
authorizer.authorize?(request, policy_set, entities) # => true
|
51
47
|
|
52
48
|
response = authorizer.authorize(request, policy_set, entities)
|
53
|
-
response.decision # => CedarPolicy::Decision
|
49
|
+
response.decision # => CedarPolicy::Decision::ALLOW
|
54
50
|
```
|
55
51
|
|
56
|
-
|
52
|
+
## Roadmap
|
53
|
+
|
54
|
+
* [ ] Add DSL to improve developer experience
|
55
|
+
* [ ] Diagnostics return with response
|
56
|
+
* [ ] Validator support
|
57
|
+
* [ ] Schema support
|
57
58
|
|
58
59
|
## Development
|
59
60
|
|
data/ext/cedar_policy/Cargo.toml
CHANGED
@@ -1,7 +1,9 @@
|
|
1
1
|
use cedar_policy::{Authorizer, Decision};
|
2
2
|
use magnus::{function, method, Error, Module, Object, RModule, Ruby};
|
3
3
|
|
4
|
-
use crate::{
|
4
|
+
use crate::{
|
5
|
+
entities::EntitiesWrapper, policy_set::RPolicySet, request::RRequest, response::RResponse,
|
6
|
+
};
|
5
7
|
|
6
8
|
#[magnus::wrap(class = "CedarPolicy::Authorizer")]
|
7
9
|
pub struct RAuthorizer(Authorizer);
|
@@ -11,18 +13,23 @@ impl RAuthorizer {
|
|
11
13
|
RAuthorizer(Authorizer::new())
|
12
14
|
}
|
13
15
|
|
14
|
-
fn is_authorized(
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
16
|
+
fn is_authorized(
|
17
|
+
&self,
|
18
|
+
request: &RRequest,
|
19
|
+
policy: &RPolicySet,
|
20
|
+
entities: EntitiesWrapper,
|
21
|
+
) -> bool {
|
22
|
+
self.0
|
23
|
+
.is_authorized(request.into(), &policy.into(), &entities.into())
|
24
|
+
.decision()
|
25
|
+
== Decision::Allow
|
19
26
|
}
|
20
27
|
|
21
28
|
fn authorize(
|
22
29
|
&self,
|
23
30
|
request: &RRequest,
|
24
31
|
policy: &RPolicySet,
|
25
|
-
entities:
|
32
|
+
entities: EntitiesWrapper,
|
26
33
|
) -> RResponse {
|
27
34
|
self.0
|
28
35
|
.is_authorized(request.into(), &policy.into(), &entities.into())
|
@@ -0,0 +1,51 @@
|
|
1
|
+
use cedar_policy::Context;
|
2
|
+
use cedar_policy_core::jsonvalue::JsonValueWithNoDuplicateKeys;
|
3
|
+
use magnus::{
|
4
|
+
value::{Lazy, ReprValue},
|
5
|
+
Error, Module, RClass, Ruby, TryConvert, Value,
|
6
|
+
};
|
7
|
+
use serde_magnus::deserialize;
|
8
|
+
|
9
|
+
use crate::CEDAR_POLICY;
|
10
|
+
|
11
|
+
static CONTEXT: Lazy<RClass> = Lazy::new(|ruby| {
|
12
|
+
ruby.get_inner(&CEDAR_POLICY)
|
13
|
+
.define_class("Context", ruby.class_object())
|
14
|
+
.unwrap()
|
15
|
+
});
|
16
|
+
|
17
|
+
pub struct ContextWrapper(Context);
|
18
|
+
|
19
|
+
impl From<ContextWrapper> for Context {
|
20
|
+
fn from(value: ContextWrapper) -> Self {
|
21
|
+
value.0
|
22
|
+
}
|
23
|
+
}
|
24
|
+
|
25
|
+
impl TryConvert for ContextWrapper {
|
26
|
+
fn try_convert(value: Value) -> Result<Self, Error> {
|
27
|
+
let handle = Ruby::get_with(value);
|
28
|
+
match value.respond_to("to_hash", false) {
|
29
|
+
Ok(true) => {
|
30
|
+
let value: Value = value.funcall_public("to_hash", ())?;
|
31
|
+
let value: JsonValueWithNoDuplicateKeys = deserialize(value)?;
|
32
|
+
Ok(Self(Context::from_json_value(value.into(), None).map_err(
|
33
|
+
|e| Error::new(handle.exception_runtime_error(), e.to_string()),
|
34
|
+
)?))
|
35
|
+
}
|
36
|
+
Err(e) => Err(Error::new(handle.exception_runtime_error(), e.to_string())),
|
37
|
+
_ => Err(Error::new(
|
38
|
+
handle.exception_arg_error(),
|
39
|
+
format!("no implicit conversion of {} into Context", unsafe {
|
40
|
+
value.classname()
|
41
|
+
}),
|
42
|
+
))?,
|
43
|
+
}
|
44
|
+
}
|
45
|
+
}
|
46
|
+
|
47
|
+
pub fn init(ruby: &Ruby) -> Result<(), Error> {
|
48
|
+
Lazy::force(&CONTEXT, ruby);
|
49
|
+
|
50
|
+
Ok(())
|
51
|
+
}
|
@@ -1,19 +1,27 @@
|
|
1
1
|
use cedar_policy::Decision;
|
2
2
|
use magnus::{
|
3
|
-
|
4
|
-
|
3
|
+
method,
|
4
|
+
typed_data::IsEql,
|
5
|
+
value::{Lazy, ReprValue},
|
6
|
+
Class, Error, IntoValue, Module, RClass, Ruby, TryConvert, Value,
|
5
7
|
};
|
6
8
|
|
7
|
-
|
8
|
-
pub struct RDecision(Decision);
|
9
|
+
use crate::CEDAR_POLICY;
|
9
10
|
|
10
|
-
|
11
|
-
|
12
|
-
|
11
|
+
static DECISION: Lazy<RClass> = Lazy::new(|ruby| {
|
12
|
+
ruby.get_inner(&CEDAR_POLICY)
|
13
|
+
.define_class("Decision", ruby.class_object())
|
14
|
+
.unwrap()
|
15
|
+
});
|
13
16
|
|
14
|
-
|
15
|
-
RDecision(Decision::
|
16
|
-
|
17
|
+
pub static DECISION_ALLOW: Lazy<Value> =
|
18
|
+
Lazy::new(|ruby| RDecision(Decision::Allow).into_value_with(ruby));
|
19
|
+
|
20
|
+
pub static DECISION_DENY: Lazy<Value> =
|
21
|
+
Lazy::new(|ruby| RDecision(Decision::Deny).into_value_with(ruby));
|
22
|
+
|
23
|
+
#[magnus::wrap(class = "CedarPolicy::Decision")]
|
24
|
+
pub struct RDecision(Decision);
|
17
25
|
|
18
26
|
impl IsEql for RDecision {
|
19
27
|
fn is_eql(&self, other: Value) -> bool {
|
@@ -42,12 +50,15 @@ impl From<Decision> for RDecision {
|
|
42
50
|
}
|
43
51
|
}
|
44
52
|
|
45
|
-
pub fn init(ruby: &Ruby
|
46
|
-
let class =
|
53
|
+
pub fn init(ruby: &Ruby) -> Result<(), Error> {
|
54
|
+
let class = ruby.get_inner(&DECISION);
|
55
|
+
let allow = ruby.get_inner(&DECISION_ALLOW);
|
56
|
+
let deny = ruby.get_inner(&DECISION_DENY);
|
57
|
+
|
47
58
|
class.undef_default_alloc_func();
|
48
59
|
|
49
|
-
class.
|
50
|
-
class.
|
60
|
+
class.const_set("ALLOW", allow)?;
|
61
|
+
class.const_set("DENY", deny)?;
|
51
62
|
|
52
63
|
class.define_method("==", method!(<RDecision as IsEql>::is_eql, 1))?;
|
53
64
|
class.define_method("eql?", method!(<RDecision as IsEql>::is_eql, 1))?;
|
@@ -1,37 +1,51 @@
|
|
1
1
|
use cedar_policy::Entities;
|
2
|
-
use
|
2
|
+
use cedar_policy_core::jsonvalue::JsonValueWithNoDuplicateKeys;
|
3
|
+
use magnus::{
|
4
|
+
value::{Lazy, ReprValue},
|
5
|
+
Error, Module, RClass, Ruby, TryConvert, Value,
|
6
|
+
};
|
7
|
+
use serde_magnus::deserialize;
|
3
8
|
|
4
|
-
use crate::
|
9
|
+
use crate::CEDAR_POLICY;
|
5
10
|
|
6
|
-
|
7
|
-
|
11
|
+
static ENTITIES: Lazy<RClass> = Lazy::new(|ruby| {
|
12
|
+
ruby.get_inner(&CEDAR_POLICY)
|
13
|
+
.define_class("Entities", ruby.class_object())
|
14
|
+
.unwrap()
|
15
|
+
});
|
8
16
|
|
9
|
-
|
10
|
-
fn new() -> Self {
|
11
|
-
Self(Entities::empty())
|
12
|
-
}
|
13
|
-
|
14
|
-
fn from_json(ruby: &Ruby, json: String) -> Result<Self, Error> {
|
15
|
-
let entities = Entities::from_json_str(&json, None)
|
16
|
-
.map_err(|error| Error::new(ruby.get_inner(&ENTITIES_ERROR), error.to_string()))?;
|
17
|
-
Ok(Self(entities))
|
18
|
-
}
|
17
|
+
pub struct EntitiesWrapper(Entities);
|
19
18
|
|
20
|
-
|
21
|
-
|
19
|
+
impl From<EntitiesWrapper> for Entities {
|
20
|
+
fn from(value: EntitiesWrapper) -> Self {
|
21
|
+
value.0
|
22
22
|
}
|
23
23
|
}
|
24
24
|
|
25
|
-
impl
|
26
|
-
fn
|
27
|
-
|
25
|
+
impl TryConvert for EntitiesWrapper {
|
26
|
+
fn try_convert(value: Value) -> Result<Self, Error> {
|
27
|
+
let handle = Ruby::get_with(value);
|
28
|
+
match value.respond_to("to_ary", false) {
|
29
|
+
Ok(true) => {
|
30
|
+
let value: Value = value.funcall_public("to_ary", ())?;
|
31
|
+
let value: JsonValueWithNoDuplicateKeys = deserialize(value)?;
|
32
|
+
Ok(Self(
|
33
|
+
Entities::from_json_value(value.into(), None)
|
34
|
+
.map_err(|e| Error::new(handle.exception_arg_error(), e.to_string()))?,
|
35
|
+
))
|
36
|
+
}
|
37
|
+
Err(e) => Err(Error::new(handle.exception_arg_error(), e.to_string())),
|
38
|
+
_ => Err(Error::new(
|
39
|
+
handle.exception_arg_error(),
|
40
|
+
format!("no implicit conversion of {} into Entities", unsafe {
|
41
|
+
value.classname()
|
42
|
+
}),
|
43
|
+
))?,
|
44
|
+
}
|
28
45
|
}
|
29
46
|
}
|
30
47
|
|
31
|
-
pub fn init(ruby: &Ruby
|
32
|
-
|
33
|
-
class.define_singleton_method("new", function!(REntities::new, 0))?;
|
34
|
-
class.define_singleton_method("from_json", function!(REntities::from_json, 1))?;
|
35
|
-
class.define_method("get", method!(REntities::get, 1))?;
|
48
|
+
pub fn init(ruby: &Ruby) -> Result<(), Error> {
|
49
|
+
Lazy::force(&ENTITIES, ruby);
|
36
50
|
Ok(())
|
37
51
|
}
|
@@ -1,54 +1,71 @@
|
|
1
|
-
use
|
1
|
+
use cedar_policy::EntityUid;
|
2
|
+
use cedar_policy_core::jsonvalue::JsonValueWithNoDuplicateKeys;
|
3
|
+
use magnus::{
|
4
|
+
value::{Lazy, ReprValue},
|
5
|
+
Class, Error, IntoValue, Module, RClass, Ruby, TryConvert, Value,
|
6
|
+
};
|
7
|
+
use serde_magnus::deserialize;
|
2
8
|
|
3
|
-
use
|
4
|
-
use magnus::{function, method, Error, Module, Object, RModule, Ruby};
|
9
|
+
use crate::CEDAR_POLICY;
|
5
10
|
|
6
|
-
|
7
|
-
|
11
|
+
static ENTITY_UID: Lazy<RClass> = Lazy::new(|ruby| {
|
12
|
+
ruby.get_inner(&CEDAR_POLICY)
|
13
|
+
.define_class("EntityUid", ruby.class_object())
|
14
|
+
.unwrap()
|
15
|
+
});
|
8
16
|
|
9
|
-
|
10
|
-
fn new(ruby: &Ruby, entity_type: String, id: String) -> Result<Self, Error> {
|
11
|
-
let id = EntityId::from_str(&id)
|
12
|
-
.map_err(|e| Error::new(ruby.exception_arg_error(), e.to_string()))?;
|
13
|
-
let entity_type = EntityTypeName::from_str(&entity_type)
|
14
|
-
.map_err(|e| Error::new(ruby.exception_arg_error(), e.to_string()))?;
|
17
|
+
pub struct EntityUidWrapper(EntityUid);
|
15
18
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
fn eq(&self, other: &REntityUid) -> bool {
|
20
|
-
self.0.eq(&other.0)
|
19
|
+
impl EntityUidWrapper {
|
20
|
+
pub fn new(uid: EntityUid) -> Self {
|
21
|
+
Self(uid)
|
21
22
|
}
|
23
|
+
}
|
22
24
|
|
23
|
-
|
24
|
-
|
25
|
+
impl From<EntityUidWrapper> for EntityUid {
|
26
|
+
fn from(value: EntityUidWrapper) -> EntityUid {
|
27
|
+
value.0
|
25
28
|
}
|
26
29
|
}
|
27
30
|
|
28
|
-
impl
|
29
|
-
fn
|
30
|
-
|
31
|
+
impl IntoValue for EntityUidWrapper {
|
32
|
+
fn into_value_with(self, handle: &Ruby) -> Value {
|
33
|
+
let type_name = self.0.type_name().to_string();
|
34
|
+
let id = self.0.id().to_string();
|
35
|
+
let class = handle.get_inner(&ENTITY_UID);
|
36
|
+
|
37
|
+
return class.new_instance((type_name, id)).unwrap().into();
|
31
38
|
}
|
32
39
|
}
|
33
40
|
|
34
|
-
impl
|
35
|
-
fn
|
36
|
-
|
41
|
+
impl TryConvert for EntityUidWrapper {
|
42
|
+
fn try_convert(value: Value) -> Result<Self, magnus::Error> {
|
43
|
+
let handle = Ruby::get_with(value);
|
44
|
+
match value.respond_to("to_hash", false) {
|
45
|
+
Ok(true) => {
|
46
|
+
let value: Value = value.funcall_public("to_hash", ())?;
|
47
|
+
let value: JsonValueWithNoDuplicateKeys = deserialize(value)?;
|
48
|
+
Ok(Self(EntityUid::from_json(value.into()).map_err(|e| {
|
49
|
+
Error::new(handle.exception_runtime_error(), e.to_string())
|
50
|
+
})?))
|
51
|
+
}
|
52
|
+
Err(e) => Err(Error::new(handle.exception_runtime_error(), e.to_string())),
|
53
|
+
_ => Err(Error::new(
|
54
|
+
handle.exception_arg_error(),
|
55
|
+
format!("no implicit conversion of {} into EntityUid", unsafe {
|
56
|
+
value.classname()
|
57
|
+
}),
|
58
|
+
))?,
|
59
|
+
}
|
37
60
|
}
|
38
61
|
}
|
39
62
|
|
40
|
-
|
41
|
-
|
42
|
-
wrapper.0.clone()
|
43
|
-
}
|
63
|
+
pub fn to_euid_value(euid: &EntityUid) -> Value {
|
64
|
+
EntityUidWrapper::new(euid.clone()).into_value_with(&Ruby::get().unwrap())
|
44
65
|
}
|
45
66
|
|
46
|
-
pub fn init(ruby: &Ruby
|
47
|
-
|
48
|
-
class.define_singleton_method("new", function!(REntityUid::new, 2))?;
|
49
|
-
class.define_method("==", method!(REntityUid::eq, 1))?;
|
50
|
-
class.define_method("to_s", method!(REntityUid::to_s, 0))?;
|
51
|
-
class.define_method("inspect", method!(REntityUid::to_s, 0))?;
|
67
|
+
pub fn init(ruby: &Ruby) -> Result<(), Error> {
|
68
|
+
Lazy::force(&ENTITY_UID, ruby);
|
52
69
|
|
53
70
|
Ok(())
|
54
71
|
}
|
data/ext/cedar_policy/src/lib.rs
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
use magnus::{value::Lazy, Error, RModule, Ruby};
|
2
2
|
|
3
3
|
mod authorizer;
|
4
|
+
mod context;
|
4
5
|
mod decision;
|
5
6
|
mod entities;
|
6
|
-
mod entity;
|
7
7
|
mod entity_uid;
|
8
8
|
mod error;
|
9
9
|
mod policy_set;
|
@@ -17,14 +17,14 @@ fn init(ruby: &Ruby) -> Result<(), Error> {
|
|
17
17
|
let module = ruby.get_inner(&CEDAR_POLICY);
|
18
18
|
|
19
19
|
error::init(ruby)?;
|
20
|
+
entity_uid::init(ruby)?;
|
21
|
+
entities::init(ruby)?;
|
22
|
+
decision::init(ruby)?;
|
23
|
+
context::init(ruby)?;
|
20
24
|
authorizer::init(ruby, &module)?;
|
21
|
-
entity_uid::init(ruby, &module)?;
|
22
|
-
entities::init(ruby, &module)?;
|
23
|
-
entity::init(ruby, &module)?;
|
24
25
|
request::init(ruby, &module)?;
|
25
26
|
response::init(ruby, &module)?;
|
26
27
|
policy_set::init(ruby, &module)?;
|
27
|
-
decision::init(ruby, &module)?;
|
28
28
|
|
29
29
|
Ok(())
|
30
30
|
}
|
@@ -1,7 +1,7 @@
|
|
1
1
|
use std::str::FromStr;
|
2
2
|
|
3
|
-
use cedar_policy::PolicySet;
|
4
|
-
use magnus::{function, method, Error, Module, Object, RModule, Ruby};
|
3
|
+
use cedar_policy::{ParseErrors, PolicySet};
|
4
|
+
use magnus::{function, method, scan_args::scan_args, Error, Module, Object, RModule, Ruby, Value};
|
5
5
|
|
6
6
|
use crate::error::PARSE_ERROR;
|
7
7
|
|
@@ -9,14 +9,15 @@ use crate::error::PARSE_ERROR;
|
|
9
9
|
pub struct RPolicySet(PolicySet);
|
10
10
|
|
11
11
|
impl RPolicySet {
|
12
|
-
fn new() -> Self {
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
12
|
+
fn new(ruby: &Ruby, args: &[Value]) -> Result<Self, Error> {
|
13
|
+
let args = scan_args::<(), _, (), (), (), ()>(args)?;
|
14
|
+
let (policy,): (Option<String>,) = args.optional;
|
15
|
+
|
16
|
+
match policy {
|
17
|
+
Some(policy) => Self::from_str(&policy)
|
18
|
+
.map_err(|e| Error::new(ruby.get_inner(&PARSE_ERROR), e.to_string())),
|
19
|
+
None => Ok(Self(PolicySet::new())),
|
20
|
+
}
|
20
21
|
}
|
21
22
|
|
22
23
|
fn is_empty(&self) -> bool {
|
@@ -30,10 +31,17 @@ impl From<&RPolicySet> for PolicySet {
|
|
30
31
|
}
|
31
32
|
}
|
32
33
|
|
34
|
+
impl FromStr for RPolicySet {
|
35
|
+
type Err = ParseErrors;
|
36
|
+
|
37
|
+
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
38
|
+
Ok(Self(PolicySet::from_str(s)?))
|
39
|
+
}
|
40
|
+
}
|
41
|
+
|
33
42
|
pub fn init(ruby: &Ruby, module: &RModule) -> Result<(), Error> {
|
34
43
|
let class = module.define_class("PolicySet", ruby.class_object())?;
|
35
|
-
class.define_singleton_method("new", function!(RPolicySet::new,
|
36
|
-
class.define_singleton_method("from_str", function!(RPolicySet::from_str, 1))?;
|
44
|
+
class.define_singleton_method("new", function!(RPolicySet::new, -1))?;
|
37
45
|
class.define_method("empty?", method!(RPolicySet::is_empty, 0))?;
|
38
46
|
|
39
47
|
Ok(())
|
@@ -1,40 +1,45 @@
|
|
1
|
-
use cedar_policy::
|
2
|
-
use magnus::{function, method, Error, Module, Object, RModule, Ruby};
|
1
|
+
use cedar_policy::Request;
|
2
|
+
use magnus::{function, method, Error, Module, Object, RModule, Ruby, Value};
|
3
3
|
use std::convert::Into;
|
4
4
|
|
5
|
-
use crate::
|
5
|
+
use crate::{
|
6
|
+
context::ContextWrapper,
|
7
|
+
entity_uid::{to_euid_value, EntityUidWrapper},
|
8
|
+
};
|
6
9
|
|
7
10
|
#[magnus::wrap(class = "CedarPolicy::Request")]
|
8
11
|
pub struct RRequest(Request);
|
9
12
|
|
10
13
|
impl RRequest {
|
11
14
|
fn new(
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
15
|
+
ruby: &Ruby,
|
16
|
+
principal: Option<EntityUidWrapper>,
|
17
|
+
action: Option<EntityUidWrapper>,
|
18
|
+
resource: Option<EntityUidWrapper>,
|
19
|
+
context: ContextWrapper,
|
20
|
+
) -> Result<Self, Error> {
|
21
|
+
Ok(Self(
|
17
22
|
Request::new(
|
18
|
-
principal.map(
|
19
|
-
action.map(
|
20
|
-
resource.map(
|
21
|
-
|
23
|
+
principal.map(|p| p.into()),
|
24
|
+
action.map(|a| a.into()),
|
25
|
+
resource.map(|r| r.into()),
|
26
|
+
context.into(),
|
22
27
|
None,
|
23
28
|
)
|
24
|
-
.
|
25
|
-
)
|
29
|
+
.map_err(|e| Error::new(ruby.exception_runtime_error(), e.to_string()))?,
|
30
|
+
))
|
26
31
|
}
|
27
32
|
|
28
|
-
fn principal(&self) -> Option<
|
29
|
-
self.0.principal().map(&
|
33
|
+
fn principal(&self) -> Option<Value> {
|
34
|
+
self.0.principal().map(&to_euid_value)
|
30
35
|
}
|
31
36
|
|
32
|
-
fn action(&self) -> Option<
|
33
|
-
self.0.action().map(&
|
37
|
+
fn action(&self) -> Option<Value> {
|
38
|
+
self.0.action().map(&to_euid_value)
|
34
39
|
}
|
35
40
|
|
36
|
-
fn resource(&self) -> Option<
|
37
|
-
self.0.resource().map(&
|
41
|
+
fn resource(&self) -> Option<Value> {
|
42
|
+
self.0.resource().map(&to_euid_value)
|
38
43
|
}
|
39
44
|
}
|
40
45
|
|
@@ -46,7 +51,7 @@ impl<'a> From<&'a RRequest> for &'a Request {
|
|
46
51
|
|
47
52
|
pub fn init(ruby: &Ruby, module: &RModule) -> Result<(), Error> {
|
48
53
|
let class = module.define_class("Request", ruby.class_object())?;
|
49
|
-
class.define_singleton_method("new", function!(RRequest::new,
|
54
|
+
class.define_singleton_method("new", function!(RRequest::new, 4))?;
|
50
55
|
class.define_method("principal", method!(RRequest::principal, 0))?;
|
51
56
|
class.define_method("action", method!(RRequest::action, 0))?;
|
52
57
|
class.define_method("resource", method!(RRequest::resource, 0))?;
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CedarPolicy
|
4
|
+
# :nodoc:
|
5
|
+
class Entities
|
6
|
+
def initialize(entities = [])
|
7
|
+
@entities = Set.new(entities)
|
8
|
+
end
|
9
|
+
|
10
|
+
def to_ary
|
11
|
+
@entities.map { |entity| CedarPolicy.deep_serialize(entity) }
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CedarPolicy
|
4
|
+
# :nodoc:
|
5
|
+
class Entity
|
6
|
+
attr_reader :uid, :attrs, :parents
|
7
|
+
|
8
|
+
def initialize(uid, attrs = {}, parents = [])
|
9
|
+
raise ArgumentError unless uid.is_a?(EntityUid)
|
10
|
+
|
11
|
+
@uid = uid
|
12
|
+
@attrs = attrs
|
13
|
+
@parents = Set.new(parents)
|
14
|
+
end
|
15
|
+
|
16
|
+
def ==(other)
|
17
|
+
hahs == other.hash
|
18
|
+
end
|
19
|
+
|
20
|
+
def hash
|
21
|
+
[self.class, @uid].hash
|
22
|
+
end
|
23
|
+
|
24
|
+
def to_hash
|
25
|
+
{
|
26
|
+
uid: @uid,
|
27
|
+
attrs: @attrs,
|
28
|
+
parents: @parents.to_a
|
29
|
+
}
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CedarPolicy
|
4
|
+
# :nodoc:
|
5
|
+
class EntityUid
|
6
|
+
attr_reader :type_name, :id
|
7
|
+
|
8
|
+
def initialize(type_name, id)
|
9
|
+
@type_name = type_name.to_s
|
10
|
+
@id = id.to_s
|
11
|
+
end
|
12
|
+
|
13
|
+
def ==(other)
|
14
|
+
hash == other.hash
|
15
|
+
end
|
16
|
+
|
17
|
+
def hash
|
18
|
+
[self.class, @type_name, @id].hash
|
19
|
+
end
|
20
|
+
|
21
|
+
def to_str
|
22
|
+
"#{@type_name}::#{@id.inspect}"
|
23
|
+
end
|
24
|
+
alias to_s to_str
|
25
|
+
alias inspect to_str
|
26
|
+
|
27
|
+
def to_hash
|
28
|
+
{ type: @type_name, id: @id }
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
data/lib/cedar_policy/version.rb
CHANGED
data/lib/cedar_policy.rb
CHANGED
@@ -1,9 +1,29 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "json"
|
4
|
+
require "set"
|
5
|
+
|
3
6
|
require_relative "cedar_policy/version"
|
4
7
|
require_relative "cedar_policy/cedar_policy"
|
8
|
+
require_relative "cedar_policy/entity_uid"
|
9
|
+
require_relative "cedar_policy/entity"
|
10
|
+
require_relative "cedar_policy/entities"
|
11
|
+
require_relative "cedar_policy/context"
|
5
12
|
|
13
|
+
# :nodoc:
|
6
14
|
module CedarPolicy
|
7
15
|
class Error < StandardError; end
|
8
|
-
|
16
|
+
|
17
|
+
def self.deep_serialize(input)
|
18
|
+
input.to_hash.each_with_object({}) do |(key, value), output|
|
19
|
+
output[key.to_sym] =
|
20
|
+
case value
|
21
|
+
when ->(h) { h.respond_to?(:to_hash) } then deep_serialize(value)
|
22
|
+
when Array
|
23
|
+
value.map { |item| item.respond_to?(:to_hash) ? deep_serialize(item) : item }
|
24
|
+
else
|
25
|
+
value
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
9
29
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cedar_policy
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Aotokitsuruya
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-08-
|
11
|
+
date: 2024-08-14 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: Ruby bindings for Cedar policy evaluation engine.
|
14
14
|
email:
|
@@ -29,9 +29,9 @@ files:
|
|
29
29
|
- ext/cedar_policy/Cargo.toml
|
30
30
|
- ext/cedar_policy/extconf.rb
|
31
31
|
- ext/cedar_policy/src/authorizer.rs
|
32
|
+
- ext/cedar_policy/src/context.rs
|
32
33
|
- ext/cedar_policy/src/decision.rs
|
33
34
|
- ext/cedar_policy/src/entities.rs
|
34
|
-
- ext/cedar_policy/src/entity.rs
|
35
35
|
- ext/cedar_policy/src/entity_uid.rs
|
36
36
|
- ext/cedar_policy/src/error.rs
|
37
37
|
- ext/cedar_policy/src/lib.rs
|
@@ -39,6 +39,10 @@ files:
|
|
39
39
|
- ext/cedar_policy/src/request.rs
|
40
40
|
- ext/cedar_policy/src/response.rs
|
41
41
|
- lib/cedar_policy.rb
|
42
|
+
- lib/cedar_policy/context.rb
|
43
|
+
- lib/cedar_policy/entities.rb
|
44
|
+
- lib/cedar_policy/entity.rb
|
45
|
+
- lib/cedar_policy/entity_uid.rb
|
42
46
|
- lib/cedar_policy/version.rb
|
43
47
|
- sig/cedar_policy.rbs
|
44
48
|
homepage: https://github.com/elct9620/cedar-policy-rb
|
@@ -1,70 +0,0 @@
|
|
1
|
-
use std::{
|
2
|
-
collections::{HashMap, HashSet},
|
3
|
-
str::FromStr,
|
4
|
-
};
|
5
|
-
|
6
|
-
use cedar_policy::{Entity, RestrictedExpression};
|
7
|
-
use magnus::{
|
8
|
-
function, method, scan_args::scan_args, Error, Module, Object, RHash, RModule, Ruby, Value,
|
9
|
-
};
|
10
|
-
|
11
|
-
use crate::{entity_uid::REntityUid, error::PARSE_ERROR};
|
12
|
-
|
13
|
-
#[magnus::wrap(class = "CedarPolicy::Entity")]
|
14
|
-
pub struct REntity(Entity);
|
15
|
-
|
16
|
-
impl REntity {
|
17
|
-
fn new(ruby: &Ruby, args: &[Value]) -> Result<REntity, Error> {
|
18
|
-
let args = scan_args::<_, _, (), (), (), ()>(args)?;
|
19
|
-
let (uid,): (&REntityUid,) = args.required;
|
20
|
-
let (attrs,): (Option<RHash>,) = args.optional;
|
21
|
-
|
22
|
-
match attrs {
|
23
|
-
Some(attrs) => Ok(Self(
|
24
|
-
Entity::new(uid.into(), try_convert_attrs(ruby, &attrs)?, HashSet::new())
|
25
|
-
.map_err(|e| Error::new(ruby.get_inner(&PARSE_ERROR), e.to_string()))?,
|
26
|
-
)),
|
27
|
-
None => Ok(Self(Entity::with_uid(uid.into()))),
|
28
|
-
}
|
29
|
-
}
|
30
|
-
|
31
|
-
fn uid(&self) -> REntityUid {
|
32
|
-
self.0.uid().into()
|
33
|
-
}
|
34
|
-
}
|
35
|
-
|
36
|
-
impl From<&Entity> for REntity {
|
37
|
-
fn from(entity: &Entity) -> Self {
|
38
|
-
Self(entity.clone())
|
39
|
-
}
|
40
|
-
}
|
41
|
-
|
42
|
-
fn to_attr(
|
43
|
-
ruby: &Ruby,
|
44
|
-
key: String,
|
45
|
-
value: String,
|
46
|
-
) -> Result<(String, RestrictedExpression), Error> {
|
47
|
-
Ok((
|
48
|
-
key,
|
49
|
-
RestrictedExpression::from_str(&value)
|
50
|
-
.map_err(|e| Error::new(ruby.get_inner(&PARSE_ERROR), e.to_string()))?,
|
51
|
-
))
|
52
|
-
}
|
53
|
-
|
54
|
-
fn try_convert_attrs(
|
55
|
-
ruby: &Ruby,
|
56
|
-
attrs: &RHash,
|
57
|
-
) -> Result<HashMap<String, RestrictedExpression>, Error> {
|
58
|
-
Ok(attrs
|
59
|
-
.to_hash_map::<String, String>()?
|
60
|
-
.iter()
|
61
|
-
.map(|(k, v)| to_attr(ruby, k.to_string(), v.to_string()))
|
62
|
-
.collect::<Result<HashMap<String, RestrictedExpression>, Error>>()?)
|
63
|
-
}
|
64
|
-
|
65
|
-
pub fn init(ruby: &Ruby, module: &RModule) -> Result<(), Error> {
|
66
|
-
let class = module.define_class("Entity", ruby.class_object())?;
|
67
|
-
class.define_singleton_method("new", function!(REntity::new, -1))?;
|
68
|
-
class.define_method("uid", method!(REntity::uid, 0))?;
|
69
|
-
Ok(())
|
70
|
-
}
|