-
Notifications
You must be signed in to change notification settings - Fork 98
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(rpc): Cookie auth system for the RPC endpoint #8900
base: main
Are you sure you want to change the base?
Conversation
Requests from a remote host that don't have the cookie generated at startup will be rejected. In zcashd, the |
We had a chat today about this with @upbqdn and @arya2, i am adding some more research here. About the cookie auth method:
https://bitcoin.org/en/release/v0.12.0#rpc-random-cookie-rpc-authentication That means the cookie method is actually for local access. I think we should focus on that in this PR. For remote access, we thought in username/password over TLS/SSL as an option. Bitcoin supported this for its RPC endpoint in the past however they don't do it anymore claiming that the RPC access should only be shared with trusted environments. It seems that the remote access should be a combination of username and password, with the additional |
Continuing with the cookie auth method, the zcash-cli sends the cookie content as basic HTTP credentials to the server: https://github.com/zcash/zcash/blob/master/src/bitcoin-cli.cpp#L251 We want to do that but just with I got confused thinking the cookie method will work for remote access, my apologies for that. |
Do we have any use cases that require authentication for local access, though? |
It's a security measure. You can't access the resources if you don't have read access to the cookie, even if you are in the same machine. |
@@ -94,6 +99,9 @@ impl Default for Config { | |||
|
|||
// Debug options are always off by default. | |||
debug_force_finished_sync: false, | |||
|
|||
// |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// | |
// Use the default cache dir for the auth cookie. |
#[rpc(name = "unauthenticated")] | ||
/// A dummy RPC method that just returns a non-authenticated RPC error. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Optional
#[rpc(name = "unauthenticated")] | |
/// A dummy RPC method that just returns a non-authenticated RPC error. | |
/// A dummy RPC method that just returns a non-authenticated RPC error. | |
#[rpc(name = "unauthenticated")] |
/// Default name for auth cookie file */ | ||
pub const COOKIEAUTH_FILE: &str = ".cookie"; | ||
|
||
/// Generate a new auth cookie and return the encoded password. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/// Generate a new auth cookie and return the encoded password. | |
/// Generate a new auth cookie and store it in the given `cookie_dir`. |
pub const COOKIEAUTH_FILE: &str = ".cookie"; | ||
|
||
/// Generate a new auth cookie and return the encoded password. | ||
pub fn generate(cookie_dir: PathBuf) -> Option<()> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Optional
Returning Result
would be more expressive.
} | ||
|
||
/// Delete the auth cookie. | ||
pub fn delete() -> Option<()> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Optional
Similarly here.
.map(|password| password.to_string()) | ||
}) | ||
.map_or(false, |password| { | ||
if let Some(cookie_password) = cookie::get(self.0.cookie_dir.clone()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We read the cookie from the disk on each check here and only rely on the OS caching the disk reads. We could keep the cookie in the memory instead. For example, by using lazy_static!
in cookie::get
.
@@ -141,4 +149,51 @@ impl FixHttpRequestMiddleware { | |||
); | |||
} | |||
} | |||
|
|||
/// Change the method name in the JSON request. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Optional
Could we move the contents of this fn to unauthenticated
and remove the fn since we call it only from there, and it only uses a single-use, hard-coded method name?
let auth_cookie = cookie::get(RpcConfig::default().cookie_dir).expect("cookie should exist"); | ||
let client = RpcRequestClient::new(zebra_rpc_address, auth_cookie); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We write the cookie to the disk, and then read it even in tests that are not related to the authentication. We could generate the cookie for tests without writing it to the disk at all, and instantiate it only through lazy_static!
.
Motivation
We want to authenticate the RPC method by the zcashd cookie method.
Solution
unauthenticated
method.Tests
PR Author's Checklist
PR Reviewer's Checklist