Add `AuthorizedOperation`
Implement `AuthorizedOperation` for `RegisterAccountRequest`, `AuthenticationTokenRequest`, `RepositoryCreateRequest`, Implement `FromOperationState` for `AuthorizedUser` and `AuthorizedInstance`, depending on the operation being `AuthorizedOperation<Object>`
parent: tbd commit: 1dcec18
Showing 4 changed files with 190 insertions and 27 deletions
giterated-daemon/src/database_backend/handler.rs
@@ -19,7 +19,7 @@ use giterated_models::{ | ||
19 | 19 | user::{User, UserRepositoriesRequest}, |
20 | 20 | value::{AnyValue, GetValue}, |
21 | 21 | }; |
22 | use giterated_stack::{AuthenticatedUser, BackendWrapper, StackOperationState}; | |
22 | use giterated_stack::{AuthenticatedUser, AuthorizedInstance, BackendWrapper, StackOperationState}; | |
23 | 23 | |
24 | 24 | use super::DatabaseBackend; |
25 | 25 | |
@@ -382,6 +382,8 @@ pub fn instance_authentication_request( | ||
382 | 382 | object: &Instance, |
383 | 383 | operation: AuthenticationTokenRequest, |
384 | 384 | state: DatabaseBackend, |
385 | // Authorizes the request for SAME-INSTANCE | |
386 | _authorized_instance: AuthorizedInstance, | |
385 | 387 | ) -> BoxFuture<'static, Result<UserAuthenticationToken, OperationError<InstanceError>>> { |
386 | 388 | let object = object.clone(); |
387 | 389 | async move { |
@@ -399,6 +401,8 @@ pub fn instance_registration_request( | ||
399 | 401 | _object: &Instance, |
400 | 402 | operation: RegisterAccountRequest, |
401 | 403 | state: DatabaseBackend, |
404 | // Authorizes the request for SAME-INSTANCE | |
405 | _authorized_instance: AuthorizedInstance, | |
402 | 406 | ) -> BoxFuture<'static, Result<UserAuthenticationToken, OperationError<InstanceError>>> { |
403 | 407 | async move { |
404 | 408 | let mut backend = state.user_backend.lock().await; |
@@ -416,6 +420,8 @@ pub fn instance_create_repository_request( | ||
416 | 420 | operation: RepositoryCreateRequest, |
417 | 421 | state: DatabaseBackend, |
418 | 422 | requester: AuthenticatedUser, |
423 | // Authorizes the request for SAME-INSTANCE | |
424 | _authorized_instance: AuthorizedInstance, | |
419 | 425 | ) -> BoxFuture<'static, Result<Repository, OperationError<InstanceError>>> { |
420 | 426 | async move { |
421 | 427 | let mut backend = state.repository_backend.lock().await; |
giterated-daemon/src/main.rs
@@ -95,6 +95,8 @@ async fn main() -> Result<(), Error> { | ||
95 | 95 | |
96 | 96 | let operation_state = { |
97 | 97 | StackOperationState { |
98 | our_instance: Instance::from_str(config["giterated"]["instance"].as_str().unwrap()) | |
99 | .unwrap(), | |
98 | 100 | giterated_backend: backend_wrapper, |
99 | 101 | instance: None, |
100 | 102 | user: None, |
giterated-models/src/lib.rs
@@ -1,3 +1,7 @@ | ||
1 | use error::OperationError; | |
2 | use object::GiteratedObject; | |
3 | use operation::GiteratedOperation; | |
4 | ||
1 | 5 | pub mod authenticated; |
2 | 6 | pub mod discovery; |
3 | 7 | pub mod error; |
giterated-stack/src/lib.rs
@@ -6,7 +6,9 @@ use std::{collections::HashMap, future::Future, ops::Deref, pin::Pin, str::FromS | ||
6 | 6 | use futures_util::FutureExt; |
7 | 7 | use giterated_models::{ |
8 | 8 | error::OperationError, |
9 | instance::Instance, | |
9 | instance::{ | |
10 | AuthenticationTokenRequest, Instance, RegisterAccountRequest, RepositoryCreateRequest, | |
11 | }, | |
10 | 12 | object::{ |
11 | 13 | AnyObject, GiteratedObject, Object, ObjectRequest, ObjectRequestError, ObjectResponse, |
12 | 14 | }, |
@@ -224,10 +226,10 @@ where | ||
224 | 226 | + Sync |
225 | 227 | + Clone, |
226 | 228 | O: GiteratedObject + Send + Sync, |
227 | D: GiteratedOperation<O> + 'static, | |
229 | D: GiteratedOperation<O> + 'static + Send + Sync, | |
228 | 230 | <D as GiteratedOperation<O>>::Failure: Send, |
229 | 231 | S: Send + Sync + Clone + 'static, |
230 | O1: FromOperationState, | |
232 | O1: FromOperationState<O, D>, | |
231 | 233 | { |
232 | 234 | fn operation_name(&self) -> &str { |
233 | 235 | D::operation_name() |
@@ -244,7 +246,7 @@ where | ||
244 | 246 | state: S, |
245 | 247 | operation_state: &StackOperationState, |
246 | 248 | ) -> Result<D::Success, OperationError<D::Failure>> { |
247 | let o1 = O1::from_state(operation_state) | |
249 | let o1 = O1::from_state(object, &operation, operation_state) | |
248 | 250 | .await |
249 | 251 | .map_err(|e| OperationError::Internal(e.to_string()))?; |
250 | 252 | self.clone()(object, operation, state, o1).await |
@@ -266,11 +268,11 @@ where | ||
266 | 268 | + Sync |
267 | 269 | + Clone, |
268 | 270 | O: GiteratedObject + Send + Sync, |
269 | D: GiteratedOperation<O> + 'static, | |
271 | D: GiteratedOperation<O> + 'static + Send + Sync, | |
270 | 272 | <D as GiteratedOperation<O>>::Failure: Send, |
271 | 273 | S: Send + Sync + Clone + 'static, |
272 | O1: FromOperationState, | |
273 | O2: FromOperationState, | |
274 | O1: FromOperationState<O, D>, | |
275 | O2: FromOperationState<O, D>, | |
274 | 276 | { |
275 | 277 | fn operation_name(&self) -> &str { |
276 | 278 | D::operation_name() |
@@ -287,10 +289,10 @@ where | ||
287 | 289 | state: S, |
288 | 290 | operation_state: &StackOperationState, |
289 | 291 | ) -> Result<D::Success, OperationError<D::Failure>> { |
290 | let o1 = O1::from_state(operation_state) | |
292 | let o1 = O1::from_state(object, &operation, operation_state) | |
291 | 293 | .await |
292 | 294 | .map_err(|e| OperationError::Internal(e.to_string()))?; |
293 | let o2 = O2::from_state(operation_state) | |
295 | let o2 = O2::from_state(object, &operation, operation_state) | |
294 | 296 | .await |
295 | 297 | .map_err(|e| OperationError::Internal(e.to_string()))?; |
296 | 298 | self.clone()(object, operation, state, o1, o2).await |
@@ -313,12 +315,12 @@ where | ||
313 | 315 | + Sync |
314 | 316 | + Clone, |
315 | 317 | O: GiteratedObject + Send + Sync, |
316 | D: GiteratedOperation<O> + 'static, | |
318 | D: GiteratedOperation<O> + 'static + Send + Sync, | |
317 | 319 | <D as GiteratedOperation<O>>::Failure: Send, |
318 | 320 | S: Send + Sync + Clone + 'static, |
319 | O1: FromOperationState, | |
320 | O2: FromOperationState, | |
321 | O3: FromOperationState, | |
321 | O1: FromOperationState<O, D>, | |
322 | O2: FromOperationState<O, D>, | |
323 | O3: FromOperationState<O, D>, | |
322 | 324 | { |
323 | 325 | fn operation_name(&self) -> &str { |
324 | 326 | D::operation_name() |
@@ -335,13 +337,13 @@ where | ||
335 | 337 | state: S, |
336 | 338 | operation_state: &StackOperationState, |
337 | 339 | ) -> Result<D::Success, OperationError<D::Failure>> { |
338 | let o1 = O1::from_state(operation_state) | |
340 | let o1 = O1::from_state(object, &operation, operation_state) | |
339 | 341 | .await |
340 | 342 | .map_err(|e| OperationError::Internal(e.to_string()))?; |
341 | let o2 = O2::from_state(operation_state) | |
343 | let o2 = O2::from_state(object, &operation, operation_state) | |
342 | 344 | .await |
343 | 345 | .map_err(|e| OperationError::Internal(e.to_string()))?; |
344 | let o3 = O3::from_state(operation_state) | |
346 | let o3 = O3::from_state(object, &operation, operation_state) | |
345 | 347 | .await |
346 | 348 | .map_err(|e| OperationError::Internal(e.to_string()))?; |
347 | 349 | self.clone()(object, operation, state, o1, o2, o3).await |
@@ -416,26 +418,42 @@ impl<S: Send + Sync + Clone + 'static> OperationWrapper<S> { | ||
416 | 418 | } |
417 | 419 | |
418 | 420 | #[async_trait::async_trait] |
419 | pub trait FromOperationState: Sized + Clone + Send { | |
421 | pub trait FromOperationState<O: GiteratedObject, D: GiteratedOperation<O> + Send + Sync>: | |
422 | Sized + Clone + Send | |
423 | { | |
420 | 424 | type Error: Serialize + DeserializeOwned; |
421 | 425 | |
422 | async fn from_state(state: &StackOperationState) -> Result<Self, OperationError<Self::Error>>; | |
426 | async fn from_state( | |
427 | object: &O, | |
428 | operation: &D, | |
429 | state: &StackOperationState, | |
430 | ) -> Result<Self, OperationError<Self::Error>>; | |
423 | 431 | } |
424 | 432 | |
425 | 433 | #[async_trait::async_trait] |
426 | impl FromOperationState for BackendWrapper { | |
434 | impl<O: GiteratedObject, D: GiteratedOperation<O> + Send + Sync> FromOperationState<O, D> | |
435 | for BackendWrapper | |
436 | { | |
427 | 437 | type Error = (); |
428 | 438 | |
429 | async fn from_state(state: &StackOperationState) -> Result<Self, OperationError<()>> { | |
439 | async fn from_state( | |
440 | _object: &O, | |
441 | _operation: &D, | |
442 | state: &StackOperationState, | |
443 | ) -> Result<Self, OperationError<()>> { | |
430 | 444 | Ok(state.giterated_backend.clone()) |
431 | 445 | } |
432 | 446 | } |
433 | 447 | |
434 | 448 | #[async_trait::async_trait] |
435 | impl FromOperationState for StackOperationState { | |
449 | impl<O: GiteratedObject, D: GiteratedOperation<O> + Send + Sync> FromOperationState<O, D> | |
450 | for StackOperationState | |
451 | { | |
436 | 452 | type Error = (); |
437 | 453 | |
438 | 454 | async fn from_state( |
455 | _object: &O, | |
456 | _operation: &D, | |
439 | 457 | state: &StackOperationState, |
440 | 458 | ) -> Result<StackOperationState, OperationError<()>> { |
441 | 459 | Ok(state.clone()) |
@@ -443,10 +461,14 @@ impl FromOperationState for StackOperationState { | ||
443 | 461 | } |
444 | 462 | |
445 | 463 | #[async_trait::async_trait] |
446 | impl FromOperationState for AuthenticatedUser { | |
464 | impl<O: GiteratedObject, D: GiteratedOperation<O> + Send + Sync> FromOperationState<O, D> | |
465 | for AuthenticatedUser | |
466 | { | |
447 | 467 | type Error = (); |
448 | 468 | |
449 | 469 | async fn from_state( |
470 | _object: &O, | |
471 | _operation: &D, | |
450 | 472 | state: &StackOperationState, |
451 | 473 | ) -> Result<AuthenticatedUser, OperationError<()>> { |
452 | 474 | state |
@@ -457,10 +479,14 @@ impl FromOperationState for AuthenticatedUser { | ||
457 | 479 | } |
458 | 480 | |
459 | 481 | #[async_trait::async_trait] |
460 | impl FromOperationState for AuthenticatedInstance { | |
482 | impl<O: GiteratedObject, D: GiteratedOperation<O> + Send + Sync> FromOperationState<O, D> | |
483 | for AuthenticatedInstance | |
484 | { | |
461 | 485 | type Error = (); |
462 | 486 | |
463 | 487 | async fn from_state( |
488 | _object: &O, | |
489 | _operation: &D, | |
464 | 490 | state: &StackOperationState, |
465 | 491 | ) -> Result<AuthenticatedInstance, OperationError<()>> { |
466 | 492 | state |
@@ -471,16 +497,141 @@ impl FromOperationState for AuthenticatedInstance { | ||
471 | 497 | } |
472 | 498 | |
473 | 499 | #[async_trait::async_trait] |
474 | impl<T: FromOperationState> FromOperationState for Option<T> { | |
500 | impl< | |
501 | T: FromOperationState<O, D> + Send + Sync, | |
502 | O: GiteratedObject + Sync, | |
503 | D: GiteratedOperation<O> + Send + Sync, | |
504 | > FromOperationState<O, D> for Option<T> | |
505 | { | |
506 | type Error = (); | |
507 | ||
508 | async fn from_state( | |
509 | object: &O, | |
510 | operation: &D, | |
511 | state: &StackOperationState, | |
512 | ) -> Result<Option<T>, OperationError<()>> { | |
513 | Ok(T::from_state(object, operation, state).await.ok()) | |
514 | } | |
515 | } | |
516 | ||
517 | #[derive(Clone)] | |
518 | pub struct AuthorizedUser(AuthenticatedUser); | |
519 | ||
520 | #[derive(Clone)] | |
521 | pub struct AuthorizedInstance(AuthenticatedInstance); | |
522 | ||
523 | #[async_trait::async_trait] | |
524 | pub trait AuthorizedOperation<O: GiteratedObject>: GiteratedOperation<O> { | |
525 | async fn authorize( | |
526 | &self, | |
527 | authorize_for: &O, | |
528 | state: &StackOperationState, | |
529 | ) -> Result<bool, OperationError<()>>; | |
530 | } | |
531 | ||
532 | #[async_trait::async_trait] | |
533 | impl AuthorizedOperation<Instance> for RegisterAccountRequest { | |
534 | async fn authorize( | |
535 | &self, | |
536 | authorize_for: &Instance, | |
537 | state: &StackOperationState, | |
538 | ) -> Result<bool, OperationError<()>> { | |
539 | if state.our_instance == *authorize_for { | |
540 | Ok(true) | |
541 | } else { | |
542 | Ok(false) | |
543 | } | |
544 | } | |
545 | } | |
546 | ||
547 | #[async_trait::async_trait] | |
548 | impl AuthorizedOperation<Instance> for AuthenticationTokenRequest { | |
549 | async fn authorize( | |
550 | &self, | |
551 | authorize_for: &Instance, | |
552 | state: &StackOperationState, | |
553 | ) -> Result<bool, OperationError<()>> { | |
554 | if state.our_instance == *authorize_for { | |
555 | Ok(true) | |
556 | } else { | |
557 | Ok(false) | |
558 | } | |
559 | } | |
560 | } | |
561 | ||
562 | #[async_trait::async_trait] | |
563 | impl AuthorizedOperation<Instance> for RepositoryCreateRequest { | |
564 | async fn authorize( | |
565 | &self, | |
566 | authorize_for: &Instance, | |
567 | state: &StackOperationState, | |
568 | ) -> Result<bool, OperationError<()>> { | |
569 | if state.our_instance == *authorize_for { | |
570 | Ok(true) | |
571 | } else { | |
572 | Ok(false) | |
573 | } | |
574 | } | |
575 | } | |
576 | ||
577 | #[async_trait::async_trait] | |
578 | impl<A: AuthorizedOperation<User> + Send + Sync> FromOperationState<User, A> for AuthorizedUser { | |
475 | 579 | type Error = (); |
476 | 580 | |
477 | async fn from_state(state: &StackOperationState) -> Result<Option<T>, OperationError<()>> { | |
478 | Ok(T::from_state(state).await.ok()) | |
581 | async fn from_state( | |
582 | object: &User, | |
583 | operation: &A, | |
584 | state: &StackOperationState, | |
585 | ) -> Result<AuthorizedUser, OperationError<()>> { | |
586 | let authenticated = AuthenticatedUser::from_state(object, operation, state).await?; | |
587 | ||
588 | match operation.authorize(object, state).await { | |
589 | Ok(authorized) => { | |
590 | assert!(authorized); | |
591 | } | |
592 | Err(err) => return Err(OperationError::Internal(err.to_string())), | |
593 | }; | |
594 | ||
595 | Ok(AuthorizedUser(authenticated)) | |
479 | 596 | } |
480 | 597 | } |
481 | 598 | |
599 | #[async_trait::async_trait] | |
600 | impl<A: AuthorizedOperation<Instance> + Send + Sync> FromOperationState<Instance, A> | |
601 | for AuthorizedInstance | |
602 | { | |
603 | type Error = (); | |
604 | ||
605 | async fn from_state( | |
606 | object: &Instance, | |
607 | operation: &A, | |
608 | state: &StackOperationState, | |
609 | ) -> Result<AuthorizedInstance, OperationError<()>> { | |
610 | let authenticated = AuthenticatedInstance::from_state(object, operation, state).await?; | |
611 | ||
612 | match operation.authorize(object, state).await { | |
613 | Ok(authorized) => { | |
614 | assert!(authorized); | |
615 | } | |
616 | Err(err) => return Err(OperationError::Internal(err.to_string())), | |
617 | }; | |
618 | ||
619 | Ok(AuthorizedInstance(authenticated)) | |
620 | } | |
621 | } | |
622 | ||
623 | // #[async_trait::async_trait> FromOperationState for Option<T> { | |
624 | // type Error = (); | |
625 | ||
626 | // async fn from_state(state: &StackOperationState) -> Result<Option<T>, OperationError<()>> { | |
627 | // Ok(T::from_state(] | |
628 | // impl<T: FromOperationStatestate).await.ok()) | |
629 | // } | |
630 | // } | |
631 | ||
482 | 632 | #[derive(Clone)] |
483 | 633 | pub struct StackOperationState { |
634 | pub our_instance: Instance, | |
484 | 635 | pub giterated_backend: BackendWrapper, |
485 | 636 | pub instance: Option<AuthenticatedInstance>, |
486 | 637 | pub user: Option<AuthenticatedUser>, |