holochain / holochain/kitsune2

Add `Access` module

Open
#263 2 comments 0 reactions 1 assignee Claimed by @mattyg View on GitHub
moss-high
Dominant language
Rust
Stars
24
Forks
15
Avg merge
2d 3h
Merged PRs (30d)
16

Description

In order to prevent read access to spaces which the existing participants want to protect, we are going to need to add access control that operates before starting to sync data with a peer.

Note that spaces in Kitsune2 are multi-tenant. Multiple agents can join a space in a single instance. When Kitsune2 communicates with remote peers, it generally doesn't care whether it's one agent or many on the other end. However, for the purposes of access, it is agents that are the actors who can provide authentication. It is also important to understand that if we sync data with one agent then we have no expectation that the data is restricted to that agent. The data is available to all agents on the remote. In which case, the definition of access is that we grant it to an agent but granting access to that agent actually opens up access to the peer where that agent is running.

Add a new module which can actively request authentication and record the results.

In order to discover which agents we need to challenge for authentication, we need to know when new agents are discovered. Adding a subscription method to the peer store would give us this ability. Similarly to the way that we subscribe to "drained" notifications on the fetch module.

The new access module will subscribe to new peers, or more accurately newly inserted peer infos even if we already knew about the agent, and check whether that agent already has access. If the agent doesn't have access then an access challenge is sent to them. This is a module message within the access module.

On receiving a challenge, the access module will respond with access credentials for the agent being challenged. For this to be a safe thing to do, the access credentials *must not* be transferable. Otherwise, it would be possible to send challenge requests to agents who are already on the network and get them to give you their access credentials which you could then use. (Given that these values have always been published to the DHT in Holochain, this was actually always a restriction).

- If the agent fails to respond, the access module will not retry. The retry will happen when the unresponsive agent produces a new agent info.
- If the agent responds then the access credentials are passed to the Kitsune2 host to be validated.
- If validation passes, the access module records that the agent has access.
- If validation fails, it is up to the host to decide what to do. The host may choose to block the agent.

When a new agent info shows up for an agent that already has access, then access is not re-checked. The challenge/respond mechanism is bypassed and the agent's access state is not changed.

The access mechanism will be an opt-out mechanism per space. The module builder should have an implementation that will come from K2 core by default and can be overriden by the host. There should also be a core no-op implementation of the module.

Suggested trait for the host to implement for checking access:

```rust
pub trait AgentAccess {
/// Provide access credentials in response to a challenge.
fn provide_access(&self, space_id: SpaceId, agent: AgentId) -> BoxFut<'static, K2Result>;

/// For a space that does use access control, check the response of a challenge.
fn check_access(&self, space_id: SpaceId, agent: AgentId, access_credentials: Bytes) -> BoxFut<'static, K2Result>;
}
```

It will cause problems if two instances of K2 on different hosts decide to use different access logic. It would also be a problem for multiple applications to want a space to be in a different state of requiring or not requiring access control. It is up to the host to try to avoid these things happening.

Suggested access module trait:

```rust
pub trait Access {
/// The module ID that this access module is running under.
///
/// Allows the network to pass messages to this module and block messages to other modules.
fn module_id(&self) -> String;

/// Whether access has been granted for a given peer.
///
/// Returns true if any agent at this peer URL has been granted access.
fn is_access_granted(&self, peer_url: Url) -> K2Result;
}
```

AC:
- A new access module is added.
- An access challenge request is sent when a peer tries to connect to us
- Add a new module to allow sending of "hello" messages that use a new ping-pong service to establish a connection. This module must be safe to use to send/receive messages without checking/challenging for access.
- The hello messages can be triggered by the Host
- The hello messages are automatically sent when:
- A new peer is added to the store with an overlapping arc
- During gossip initiation, if we have no preferred peers to talk to
- A core implementation of the access module is provided that checks access by dynamically calling a validator function provided by the host.
- Network messages to or from any module other than the loaded access module are blocked until the access module grants access to a given peer URL.
- The kitsune space factory should enforce that the host provides an access module factory that decides what access module to use. The space ID will be provided to the access module factory so that the host can decide depending on logic for each space.
- The test builder for the kitsune space factory should set the access module builder to provide the no-op implementation of the access module by default.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.