mirror of
https://github.com/pfzetto/rebacs
synced 2024-11-22 19:22:51 +01:00
added authentication
This commit is contained in:
parent
f368a85317
commit
dbd581cece
6 changed files with 251 additions and 26 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -2,3 +2,4 @@
|
||||||
.env
|
.env
|
||||||
graph.dat
|
graph.dat
|
||||||
graph.dat.bak
|
graph.dat.bak
|
||||||
|
api_keys.dat
|
||||||
|
|
79
Cargo.lock
generated
79
Cargo.lock
generated
|
@ -124,6 +124,15 @@ version = "1.3.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "block-buffer"
|
||||||
|
version = "0.10.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
|
||||||
|
dependencies = [
|
||||||
|
"generic-array",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bumpalo"
|
name = "bumpalo"
|
||||||
version = "3.12.1"
|
version = "3.12.1"
|
||||||
|
@ -148,6 +157,35 @@ version = "1.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cpufeatures"
|
||||||
|
version = "0.2.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3e4c1eaa2012c47becbbad2ab175484c2a84d1185b566fb2cc5b8707343dfe58"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crypto-common"
|
||||||
|
version = "0.1.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
|
||||||
|
dependencies = [
|
||||||
|
"generic-array",
|
||||||
|
"typenum",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "digest"
|
||||||
|
version = "0.10.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f"
|
||||||
|
dependencies = [
|
||||||
|
"block-buffer",
|
||||||
|
"crypto-common",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dotenvy"
|
name = "dotenvy"
|
||||||
version = "0.15.7"
|
version = "0.15.7"
|
||||||
|
@ -254,6 +292,16 @@ dependencies = [
|
||||||
"pin-utils",
|
"pin-utils",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "generic-array"
|
||||||
|
version = "0.14.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
|
||||||
|
dependencies = [
|
||||||
|
"typenum",
|
||||||
|
"version_check",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "getrandom"
|
name = "getrandom"
|
||||||
version = "0.2.9"
|
version = "0.2.9"
|
||||||
|
@ -320,6 +368,12 @@ version = "0.3.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286"
|
checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hex"
|
||||||
|
version = "0.4.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "http"
|
name = "http"
|
||||||
version = "0.2.9"
|
version = "0.2.9"
|
||||||
|
@ -884,6 +938,17 @@ dependencies = [
|
||||||
"syn 2.0.15",
|
"syn 2.0.15",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sha2"
|
||||||
|
version = "0.10.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"cpufeatures",
|
||||||
|
"digest",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "signal-hook-registry"
|
name = "signal-hook-registry"
|
||||||
version = "1.4.1"
|
version = "1.4.1"
|
||||||
|
@ -979,10 +1044,12 @@ name = "themis"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"dotenvy",
|
"dotenvy",
|
||||||
|
"hex",
|
||||||
"log",
|
"log",
|
||||||
"pretty_env_logger",
|
"pretty_env_logger",
|
||||||
"prost",
|
"prost",
|
||||||
"serde",
|
"serde",
|
||||||
|
"sha2",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tonic",
|
"tonic",
|
||||||
"tonic-build",
|
"tonic-build",
|
||||||
|
@ -1177,6 +1244,12 @@ version = "0.2.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed"
|
checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "typenum"
|
||||||
|
version = "1.16.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-ident"
|
name = "unicode-ident"
|
||||||
version = "1.0.8"
|
version = "1.0.8"
|
||||||
|
@ -1189,6 +1262,12 @@ version = "0.7.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a"
|
checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "version_check"
|
||||||
|
version = "0.9.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "want"
|
name = "want"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
|
|
|
@ -13,6 +13,8 @@ pretty_env_logger = "0.4.0"
|
||||||
dotenvy = "0.15.7"
|
dotenvy = "0.15.7"
|
||||||
tonic = { version="0.9.2", features=["tls"] }
|
tonic = { version="0.9.2", features=["tls"] }
|
||||||
prost = "0.11.9"
|
prost = "0.11.9"
|
||||||
|
sha2 = "0.10.6"
|
||||||
|
hex = "0.4.3"
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
tonic-build = "0.9.2"
|
tonic-build = "0.9.2"
|
||||||
|
|
52
src/graph.rs
52
src/graph.rs
|
@ -251,13 +251,20 @@ impl Graph {
|
||||||
let arr = arr
|
let arr = arr
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|x| {
|
.filter_map(|x| {
|
||||||
let obj_ref = x.object_ref();
|
let rel_obj_ref = x.object_ref();
|
||||||
self.nodes.get_by_b(obj_ref).map(|obj| {
|
self.nodes.get_by_b(rel_obj_ref).map(|rel_obj| {
|
||||||
let (namespace, id) = (&obj.namespace, &obj.id);
|
let (namespace, id) = (&rel_obj.namespace, &rel_obj.id);
|
||||||
|
|
||||||
match x.relation() {
|
if *namespace == obj.namespace && *id == obj.id {
|
||||||
None => format!("{}:{}", &namespace, &id),
|
match x.relation() {
|
||||||
Some(rel) => format!("{}:{}#{}", &namespace, &id, &rel.0),
|
None => "self".to_string(),
|
||||||
|
Some(rel) => format!("self#{}", &rel.0),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
match x.relation() {
|
||||||
|
None => format!("{}:{}", &namespace, &id),
|
||||||
|
Some(rel) => format!("{}:{}#{}", &namespace, &id, &rel.0),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -277,16 +284,17 @@ impl Graph {
|
||||||
let mut lines = reader.lines();
|
let mut lines = reader.lines();
|
||||||
let mut graph = Graph::default();
|
let mut graph = Graph::default();
|
||||||
|
|
||||||
let mut node: Option<ObjectRef> = None;
|
let mut node: Option<(ObjectRef, String, String)> = None;
|
||||||
let mut relations = vec![];
|
let mut relations = vec![];
|
||||||
while let Ok(Some(line)) = lines.next_line().await {
|
while let Ok(Some(line)) = lines.next_line().await {
|
||||||
if line.starts_with('[') && line.ends_with(']') {
|
if line.starts_with('[') && line.ends_with(']') {
|
||||||
let line = &mut line[1..line.len() - 1].split(':');
|
let line = &mut line[1..line.len() - 1].split(':');
|
||||||
let obj_ref =
|
let namespace = line.next().unwrap();
|
||||||
graph.add_node(Object::new(line.next().unwrap(), line.next().unwrap()));
|
let id = line.next().unwrap();
|
||||||
node = Some(obj_ref);
|
let obj_ref = graph.add_node(Object::new(namespace, id));
|
||||||
|
node = Some((obj_ref, namespace.to_string(), id.to_string()));
|
||||||
} else if line.contains('=') && line.contains('[') && line.contains(']') {
|
} else if line.contains('=') && line.contains('[') && line.contains(']') {
|
||||||
if let Some(dst) = node {
|
if let Some(dst) = &node {
|
||||||
let equals_pos = line.find('=').unwrap();
|
let equals_pos = line.find('=').unwrap();
|
||||||
let arr_start = line.find('[').unwrap();
|
let arr_start = line.find('[').unwrap();
|
||||||
let arr_stop = line.find(']').unwrap();
|
let arr_stop = line.find(']').unwrap();
|
||||||
|
@ -296,20 +304,26 @@ impl Graph {
|
||||||
|
|
||||||
for obj in arr {
|
for obj in arr {
|
||||||
let (src_namespace, src_id, src_rel) = if obj.contains('#') {
|
let (src_namespace, src_id, src_rel) = if obj.contains('#') {
|
||||||
let sep_1 = obj.find(':').unwrap();
|
let sep_1 = obj.find(':');
|
||||||
let sep_2 = obj.find('#').unwrap();
|
let sep_2 = obj.find('#').unwrap();
|
||||||
|
|
||||||
let namespace = &obj[..sep_1];
|
let (namespace, id) = if let Some(sep_1) = sep_1 {
|
||||||
let id = &obj[sep_1 + 1..sep_2];
|
(&obj[..sep_1], &obj[sep_1 + 1..sep_2])
|
||||||
|
} else {
|
||||||
|
(dst.1.as_str(), dst.2.as_str())
|
||||||
|
};
|
||||||
|
|
||||||
let rel = &obj[sep_2 + 1..];
|
let rel = &obj[sep_2 + 1..];
|
||||||
|
|
||||||
(namespace, id, Some(rel))
|
(namespace, id, Some(rel))
|
||||||
} else {
|
} else {
|
||||||
let sep_1 = obj.find(':').unwrap();
|
let sep_1 = obj.find(':');
|
||||||
|
|
||||||
let namespace = &obj[..sep_1];
|
|
||||||
let id = &obj[sep_1 + 1..];
|
|
||||||
|
|
||||||
|
let (namespace, id) = if let Some(sep_1) = sep_1 {
|
||||||
|
(&obj[..sep_1], &obj[sep_1 + 1..])
|
||||||
|
} else {
|
||||||
|
(dst.1.as_str(), dst.2.as_str())
|
||||||
|
};
|
||||||
(namespace, id, None)
|
(namespace, id, None)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -317,7 +331,7 @@ impl Graph {
|
||||||
src_namespace.to_string(),
|
src_namespace.to_string(),
|
||||||
src_id.to_string(),
|
src_id.to_string(),
|
||||||
src_rel.map(String::from),
|
src_rel.map(String::from),
|
||||||
dst,
|
dst.0,
|
||||||
rel.to_string(),
|
rel.to_string(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,11 @@
|
||||||
|
use std::collections::HashMap;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use log::info;
|
use log::info;
|
||||||
|
use sha2::{Digest, Sha256};
|
||||||
use tokio::sync::mpsc::Sender;
|
use tokio::sync::mpsc::Sender;
|
||||||
use tokio::sync::Mutex;
|
use tokio::sync::Mutex;
|
||||||
|
use tonic::metadata::MetadataMap;
|
||||||
use tonic::{Request, Response, Status};
|
use tonic::{Request, Response, Status};
|
||||||
|
|
||||||
use crate::graph::{self, Graph, ObjectRelation};
|
use crate::graph::{self, Graph, ObjectRelation};
|
||||||
|
@ -14,6 +17,7 @@ use crate::themis_proto::{
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct GraphService {
|
pub struct GraphService {
|
||||||
|
pub api_keys: Arc<Mutex<HashMap<String, String>>>,
|
||||||
pub graph: Arc<Mutex<Graph>>,
|
pub graph: Arc<Mutex<Graph>>,
|
||||||
pub save_trigger: Sender<()>,
|
pub save_trigger: Sender<()>,
|
||||||
}
|
}
|
||||||
|
@ -23,6 +27,15 @@ impl ObjectService for GraphService {
|
||||||
async fn create(&self, request: Request<Object>) -> Result<Response<Empty>, Status> {
|
async fn create(&self, request: Request<Object>) -> Result<Response<Empty>, Status> {
|
||||||
let mut graph = self.graph.lock().await;
|
let mut graph = self.graph.lock().await;
|
||||||
|
|
||||||
|
authenticate(
|
||||||
|
request.metadata(),
|
||||||
|
&graph,
|
||||||
|
&self.api_keys,
|
||||||
|
&request.get_ref().namespace,
|
||||||
|
"write",
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
if request.get_ref().namespace.is_empty() || request.get_ref().id.is_empty() {
|
if request.get_ref().namespace.is_empty() || request.get_ref().id.is_empty() {
|
||||||
return Err(Status::invalid_argument("namespace and id must be set"));
|
return Err(Status::invalid_argument("namespace and id must be set"));
|
||||||
}
|
}
|
||||||
|
@ -45,6 +58,15 @@ impl ObjectService for GraphService {
|
||||||
async fn delete(&self, request: Request<Object>) -> Result<Response<Empty>, Status> {
|
async fn delete(&self, request: Request<Object>) -> Result<Response<Empty>, Status> {
|
||||||
let mut graph = self.graph.lock().await;
|
let mut graph = self.graph.lock().await;
|
||||||
|
|
||||||
|
authenticate(
|
||||||
|
request.metadata(),
|
||||||
|
&graph,
|
||||||
|
&self.api_keys,
|
||||||
|
&request.get_ref().namespace,
|
||||||
|
"write",
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
if request.get_ref().namespace.is_empty() || request.get_ref().id.is_empty() {
|
if request.get_ref().namespace.is_empty() || request.get_ref().id.is_empty() {
|
||||||
return Err(Status::invalid_argument("namespace and id must be set"));
|
return Err(Status::invalid_argument("namespace and id must be set"));
|
||||||
}
|
}
|
||||||
|
@ -67,6 +89,15 @@ impl ObjectService for GraphService {
|
||||||
async fn exists(&self, request: Request<Object>) -> Result<Response<ExistsResponse>, Status> {
|
async fn exists(&self, request: Request<Object>) -> Result<Response<ExistsResponse>, Status> {
|
||||||
let graph = self.graph.lock().await;
|
let graph = self.graph.lock().await;
|
||||||
|
|
||||||
|
authenticate(
|
||||||
|
request.metadata(),
|
||||||
|
&graph,
|
||||||
|
&self.api_keys,
|
||||||
|
&request.get_ref().namespace,
|
||||||
|
"read",
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
if request.get_ref().namespace.is_empty() || request.get_ref().id.is_empty() {
|
if request.get_ref().namespace.is_empty() || request.get_ref().id.is_empty() {
|
||||||
return Err(Status::invalid_argument("namespace and id must be set"));
|
return Err(Status::invalid_argument("namespace and id must be set"));
|
||||||
}
|
}
|
||||||
|
@ -84,7 +115,16 @@ impl RelationService for GraphService {
|
||||||
async fn create(&self, request: Request<Relation>) -> Result<Response<Empty>, Status> {
|
async fn create(&self, request: Request<Relation>) -> Result<Response<Empty>, Status> {
|
||||||
let mut graph = self.graph.lock().await;
|
let mut graph = self.graph.lock().await;
|
||||||
|
|
||||||
let (src, dst) = transform_relation(request.get_ref(), &graph)?;
|
let (src, dst, dst_namespace) = transform_relation(request.get_ref(), &graph)?;
|
||||||
|
|
||||||
|
authenticate(
|
||||||
|
request.metadata(),
|
||||||
|
&graph,
|
||||||
|
&self.api_keys,
|
||||||
|
&dst_namespace,
|
||||||
|
"write",
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
graph.add_relation(src, dst);
|
graph.add_relation(src, dst);
|
||||||
|
|
||||||
|
@ -97,7 +137,16 @@ impl RelationService for GraphService {
|
||||||
async fn delete(&self, request: Request<Relation>) -> Result<Response<Empty>, Status> {
|
async fn delete(&self, request: Request<Relation>) -> Result<Response<Empty>, Status> {
|
||||||
let mut graph = self.graph.lock().await;
|
let mut graph = self.graph.lock().await;
|
||||||
|
|
||||||
let (src, dst) = transform_relation(request.get_ref(), &graph)?;
|
let (src, dst, dst_namespace) = transform_relation(request.get_ref(), &graph)?;
|
||||||
|
|
||||||
|
authenticate(
|
||||||
|
request.metadata(),
|
||||||
|
&graph,
|
||||||
|
&self.api_keys,
|
||||||
|
&dst_namespace,
|
||||||
|
"write",
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
graph.remove_relation(src, dst);
|
graph.remove_relation(src, dst);
|
||||||
|
|
||||||
|
@ -110,7 +159,16 @@ impl RelationService for GraphService {
|
||||||
async fn exists(&self, request: Request<Relation>) -> Result<Response<ExistsResponse>, Status> {
|
async fn exists(&self, request: Request<Relation>) -> Result<Response<ExistsResponse>, Status> {
|
||||||
let graph = self.graph.lock().await;
|
let graph = self.graph.lock().await;
|
||||||
|
|
||||||
let (src, dst) = transform_relation(request.get_ref(), &graph)?;
|
let (src, dst, dst_namespace) = transform_relation(request.get_ref(), &graph)?;
|
||||||
|
|
||||||
|
authenticate(
|
||||||
|
request.metadata(),
|
||||||
|
&graph,
|
||||||
|
&self.api_keys,
|
||||||
|
&dst_namespace,
|
||||||
|
"read",
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
let exists = graph.has_relation(src, dst);
|
let exists = graph.has_relation(src, dst);
|
||||||
|
|
||||||
|
@ -126,7 +184,7 @@ impl QueryService for GraphService {
|
||||||
) -> Result<Response<IsRelatedToResponse>, Status> {
|
) -> Result<Response<IsRelatedToResponse>, Status> {
|
||||||
let graph = self.graph.lock().await;
|
let graph = self.graph.lock().await;
|
||||||
|
|
||||||
let related = if let Ok((src, dst)) = transform_relation(request.get_ref(), &graph) {
|
let related = if let Ok((src, dst, _)) = transform_relation(request.get_ref(), &graph) {
|
||||||
graph.is_related_to(src, dst)
|
graph.is_related_to(src, dst)
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
|
@ -140,9 +198,19 @@ impl QueryService for GraphService {
|
||||||
) -> Result<Response<GetRelatedToResponse>, Status> {
|
) -> Result<Response<GetRelatedToResponse>, Status> {
|
||||||
let graph = self.graph.lock().await;
|
let graph = self.graph.lock().await;
|
||||||
|
|
||||||
|
authenticate(
|
||||||
|
request.metadata(),
|
||||||
|
&graph,
|
||||||
|
&self.api_keys,
|
||||||
|
&request.get_ref().namespace,
|
||||||
|
"read",
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
let obj = graph
|
let obj = graph
|
||||||
.get_node(&request.get_ref().namespace, &request.get_ref().id)
|
.get_node(&request.get_ref().namespace, &request.get_ref().id)
|
||||||
.ok_or(Status::not_found("object not found"))?;
|
.ok_or(Status::not_found("object not found"))?;
|
||||||
|
|
||||||
let rel = graph::Relation::new(&request.get_ref().relation);
|
let rel = graph::Relation::new(&request.get_ref().relation);
|
||||||
|
|
||||||
Ok(Response::new(GetRelatedToResponse {
|
Ok(Response::new(GetRelatedToResponse {
|
||||||
|
@ -174,6 +242,16 @@ impl QueryService for GraphService {
|
||||||
.object
|
.object
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.ok_or(Status::invalid_argument("object must be set"))?;
|
.ok_or(Status::invalid_argument("object must be set"))?;
|
||||||
|
|
||||||
|
authenticate(
|
||||||
|
request.metadata(),
|
||||||
|
&graph,
|
||||||
|
&self.api_keys,
|
||||||
|
&obj.namespace,
|
||||||
|
"read",
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
let obj = graph
|
let obj = graph
|
||||||
.get_node(&obj.namespace, &obj.id)
|
.get_node(&obj.namespace, &obj.id)
|
||||||
.ok_or(Status::not_found("object not found"))?;
|
.ok_or(Status::not_found("object not found"))?;
|
||||||
|
@ -200,7 +278,7 @@ impl QueryService for GraphService {
|
||||||
fn transform_relation(
|
fn transform_relation(
|
||||||
rel: &Relation,
|
rel: &Relation,
|
||||||
graph: &Graph,
|
graph: &Graph,
|
||||||
) -> Result<(graph::ObjectOrSet, graph::ObjectRelation), Status> {
|
) -> Result<(graph::ObjectOrSet, graph::ObjectRelation, String), Status> {
|
||||||
let src = match rel
|
let src = match rel
|
||||||
.src
|
.src
|
||||||
.as_ref()
|
.as_ref()
|
||||||
|
@ -223,10 +301,46 @@ fn transform_relation(
|
||||||
.dst
|
.dst
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.ok_or(Status::invalid_argument("dst must be set"))?;
|
.ok_or(Status::invalid_argument("dst must be set"))?;
|
||||||
|
let dst_namespace = dst.namespace.to_string();
|
||||||
let dst = graph
|
let dst = graph
|
||||||
.get_node(&dst.namespace, &dst.id)
|
.get_node(&dst.namespace, &dst.id)
|
||||||
.ok_or(Status::not_found("dst object could not be found"))?;
|
.ok_or(Status::not_found("dst object could not be found"))?;
|
||||||
let dst = ObjectRelation(dst, graph::Relation::new(&rel.relation));
|
let dst = ObjectRelation(dst, graph::Relation::new(&rel.relation));
|
||||||
|
|
||||||
Ok((src, dst))
|
Ok((src, dst, dst_namespace))
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn authenticate(
|
||||||
|
metadata: &MetadataMap,
|
||||||
|
graph: &Graph,
|
||||||
|
api_keys: &Arc<Mutex<HashMap<String, String>>>,
|
||||||
|
namespace: &str,
|
||||||
|
relation: &str,
|
||||||
|
) -> Result<(), Status> {
|
||||||
|
let api_key = metadata
|
||||||
|
.get("x-api-key")
|
||||||
|
.map(|x| x.to_str().unwrap())
|
||||||
|
.ok_or(Status::unauthenticated("x-api-key required"))?;
|
||||||
|
|
||||||
|
let mut hasher = Sha256::new();
|
||||||
|
hasher.update(api_key);
|
||||||
|
let api_key = hex::encode(hasher.finalize());
|
||||||
|
let api_keys = api_keys.lock().await;
|
||||||
|
let api_key = api_keys
|
||||||
|
.get(&api_key)
|
||||||
|
.ok_or(Status::unauthenticated("api-key invalid"))?;
|
||||||
|
|
||||||
|
let api_key = graph
|
||||||
|
.get_node("themis_key", api_key)
|
||||||
|
.ok_or(Status::unauthenticated("api-key invalid"))?;
|
||||||
|
|
||||||
|
let ns_ref = graph
|
||||||
|
.get_node("themis_ns", namespace)
|
||||||
|
.ok_or(Status::permission_denied("no permission for namespace"))?;
|
||||||
|
|
||||||
|
if !graph.is_related_to(api_key, (ns_ref, graph::Relation::new(relation))) {
|
||||||
|
Err(Status::permission_denied("no permission for namespace"))
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
17
src/main.rs
17
src/main.rs
|
@ -1,9 +1,10 @@
|
||||||
use std::{sync::Arc, time::Duration};
|
use std::{collections::HashMap, sync::Arc, time::Duration};
|
||||||
|
|
||||||
use graph::Graph;
|
use graph::Graph;
|
||||||
use grpc_service::GraphService;
|
use grpc_service::GraphService;
|
||||||
use tokio::{
|
use tokio::{
|
||||||
fs::{self, File},
|
fs::{self, File},
|
||||||
|
io::{AsyncBufReadExt, BufReader},
|
||||||
select,
|
select,
|
||||||
sync::{mpsc::channel, Mutex},
|
sync::{mpsc::channel, Mutex},
|
||||||
};
|
};
|
||||||
|
@ -23,6 +24,19 @@ async fn main() {
|
||||||
dotenvy::dotenv().ok();
|
dotenvy::dotenv().ok();
|
||||||
pretty_env_logger::init();
|
pretty_env_logger::init();
|
||||||
|
|
||||||
|
let mut api_keys = HashMap::new();
|
||||||
|
if let Ok(file) = File::open("api_keys.dat").await {
|
||||||
|
let reader = BufReader::new(file);
|
||||||
|
let mut lines = reader.lines();
|
||||||
|
while let Ok(Some(line)) = lines.next_line().await {
|
||||||
|
let line = line.replace(' ', "");
|
||||||
|
let mut line = line.split('=');
|
||||||
|
let name = line.next().unwrap().to_string();
|
||||||
|
let hash = line.next().unwrap().to_string();
|
||||||
|
api_keys.insert(hash, name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let graph = if let Ok(mut file) = File::open("graph.dat").await {
|
let graph = if let Ok(mut file) = File::open("graph.dat").await {
|
||||||
Graph::from_file(&mut file).await
|
Graph::from_file(&mut file).await
|
||||||
} else {
|
} else {
|
||||||
|
@ -48,6 +62,7 @@ async fn main() {
|
||||||
});
|
});
|
||||||
|
|
||||||
let graph_service = GraphService {
|
let graph_service = GraphService {
|
||||||
|
api_keys: Arc::new(Mutex::new(api_keys)),
|
||||||
graph: graph.clone(),
|
graph: graph.clone(),
|
||||||
save_trigger: save_tx.clone(),
|
save_trigger: save_tx.clone(),
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue