casbin-rs / casbin-grpc

Casbin-gRPC provides gRPC interface for Casbin authorization which is implemented with Rust.
https://github.com/casbin/casbin-server
Apache License 2.0
7 stars 4 forks source link

Setting `new_enforcer` function #13

Open SiddheshKanawade opened 1 year ago

SiddheshKanawade commented 1 year ago

I am trying to draft the new_enforcer, which is as below:

 async fn new_enforcer(
        &self,
        i: Request<casbin_proto::NewEnforcerRequest>,
    ) -> Result<Response<casbin_proto::NewEnforcerReply>, Status> {
        let mut a: Option<Box<dyn Adapter>> = None;
        let e: CachedEnforcer;

        let get_inner = i.into_inner();

        if get_inner.adapter_handle != -1 {
            a = match self.get_adapter(get_inner.adapter_handle).await {
                Ok(&v) => Some(v),
                Err(_) => return Ok(Response::new(casbin_proto::NewEnforcerReply { handler: 0 })),
            };
        }

        if get_inner.model_text == String::from("") {
            let cfg = adapter::load_configuration("config/connection_config.json").await?;
            let data = match std::fs::read_to_string(cfg.enforcer.as_str()) {
                Ok(v) => v,
                Err(_) => return Ok(Response::new(casbin_proto::NewEnforcerReply { handler: 0 })),
            };
        }

        if a.is_none() {
            let m = match DefaultModel::from_str(get_inner.model_text.as_str()).await {
                Ok(v) => v,
                Err(_) => return Ok(Response::new(casbin_proto::NewEnforcerReply { handler: 0 })),
            };
            e = match casbin::CachedEnforcer::new(m, ()).await {
                Ok(v) => v,
                Err(_) => return Ok(Response::new(casbin_proto::NewEnforcerReply { handler: 0 })),
            };
        } else {
            let m = match DefaultModel::from_str(get_inner.model_text.as_str()).await {
                Ok(v) => v,
                Err(_) => return Ok(Response::new(casbin_proto::NewEnforcerReply { handler: 0 })),
            };

            e = match casbin::CachedEnforcer::new(m, a).await {
                Ok(v) => v,
                Err(er) => return Ok(Response::new(casbin_proto::NewEnforcerReply { handler: 0 })),
            };
        }

        let epass = Arc::new(Mutex::new(e));
        let h = self.add_enforcer(epass);
        Ok(Response::new(casbin_proto::NewEnforcerReply { handler: h }))
    }

Here I am getting error in self.get_adapter() and self.add_enforcer()function, the error message is as follows:

error[E0507]: cannot move out of a shared reference
   --> src/server/rpc_calls.rs:355:23
    |
355 |             a = match self.get_adapter(get_inner.adapter_handle).await {
    |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
356 |                 Ok(&v) => Some(v),
    |                     -
    |                     |
    |                     data moved here
    |                     move occurs because `v` has type `Box<dyn Adapter>`, which does not implement the `Copy` trait
error[E0596]: cannot borrow `*__self` as mutable, as it is behind a `&` reference
   --> src/server/rpc_calls.rs:391:17
    |
346 |         &self,
    |          ---- help: consider changing this to be a mutable reference: `&mut CasbinGRPC`
...
391 |         let h = self.add_enforcer(epass);
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^ `__self` is a `&` reference, so the data it refers to cannot be borrowed as mutable

After the initial research I was able to figure out that this is due to the & reference from the get_adapter function, which is as below:

pub async fn get_adapter(&self, handle: i32) -> Result<&Box<dyn Adapter>, &str> {
        self.adapter_map.get(&handle).ok_or("No adapter found")
    }

Here, adapter_map is a hashmap:

pub struct CasbinGRPC {
    enforcer_map: HashMap<i32, Arc<Mutex<CachedEnforcer>>>,
    adapter_map: HashMap<i32, Box<dyn Adapter>>,
}

When we take any value from the hashmap, we get the reference of that value rather than the copy of the value. In short, when we do self.adapter_map.get(&handle), we get &Box<dyn Adapter> and not Box<dyn Adapter>. Since Copy trait is not implemented for Adapter in the casbin-rs, we can't use methods like to_owned to drop the &. I tried to send the Box<dyn Adapter> wrapped in Arc<Mutex<Box<dyn Adapter>>> but then in convert.rs of casbin-rs we can't call TryIntoAdapter for it.

I am unable to figure out how can I resolve the above errors.

SiddheshKanawade commented 1 year ago

@hsluoyz @hackerchai @PsiACE please help

SiddheshKanawade commented 1 year ago

I tried to send the adapter as wrapped under RefCell but since its not thread safe, I am unable to use it. The major cause of error is due to &Box<dyn Adapter> instead of Box<dyn Adapter> on calling by key from hashmap. As of now, I am able to thing of the following possible approaches:

  1. Make another datastructure similar to hashmap which will return required Box<dyn Adapter>
  2. Make some changes in casbin-rs as that it can implement TryIntoAdapter for Arc<Mutex<T>>.

In this first approach, I think we will loose the optimisation and hence was planning to go with the second one. @hsluoyz @hackerchai is it fine if I make some changes in casbin-rs?

Until then I will try to close the other issues in sqlx-adapter and casbin-actix-auth

Update: sqlx adapter issue has been resolved

SiddheshKanawade commented 1 year ago

@hackerchai @hsluoyz can you please comment on above issue and give your views. I have tried every possible thing I could think of, adapter doesn’t have clone or copy traits implemented, hence can’t directly copy it without taking reference.

hsluoyz commented 1 year ago

@SiddheshKanawade plz contact @hackerchai

SiddheshKanawade commented 1 year ago

@SiddheshKanawade plz contact @hackerchai

Will dm him too, it seems he isn’t active over here recently. Till then I am working on diesel adapter #66