Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
a500928
feat: Add identity manager
eftychis Feb 5, 2020
bfd55e7
address; change to non-ephemeral
eftychis Feb 15, 2020
93366c3
Document; minor
eftychis Feb 17, 2020
b17201b
Merge remote-tracking branch 'origin/master' into eftychis-identity-s…
eftychis Feb 17, 2020
81bc873
Rv partial changes
eftychis Feb 17, 2020
c2e9e66
Merge branch 'master' into eftychis-identity-skeleton
eftychis Feb 18, 2020
bbf8616
Merge branch 'master' into eftychis-identity-skeleton
eftychis Feb 19, 2020
4ff91d2
Merge remote-tracking branch 'origin/master' into eftychis-identity-s…
eftychis Feb 25, 2020
6e628bc
Add signer trait to the agent
eftychis Feb 26, 2020
6e3eeb6
Merge branch 'master' into eftychis-identity-skeleton
eftychis Feb 26, 2020
50d3a25
Merge branch 'master' into eftychis-identity-skeleton
eftychis Feb 27, 2020
6949f48
Merge branch 'master' into eftychis-identity-skeleton
eftychis Feb 28, 2020
bae8077
rename
eftychis Feb 28, 2020
cff25b4
fixup! rename
eftychis Mar 2, 2020
cd2c685
fixup! rename (2)
eftychis Mar 2, 2020
8ea519f
Merge branch 'master' into eftychis-identity-skeleton
eftychis Mar 2, 2020
e866c0d
Add AsRef for Principals
eftychis Mar 5, 2020
54f093b
Merge remote-tracking branch 'origin/master' into eftychis-identity-s…
eftychis Mar 9, 2020
4fd305c
Merge branch 'master' into eftychis-identity-skeleton
eftychis Mar 9, 2020
520ba74
Document; Add Readme; Rm main; Rename module to types
eftychis Mar 9, 2020
c1e4002
Move improvements to skeleton branch
eftychis Mar 10, 2020
6184fe7
Remove interfaces for now
eftychis Mar 13, 2020
6abb4fd
Integrate identity manager attempt 2
eftychis Mar 9, 2020
7996cb6
Add profile path under .cache/dfinity/
eftychis Mar 11, 2020
876d3f2
Store Key files locally in a project
eftychis Mar 16, 2020
9207303
Remove documentation
eftychis Mar 16, 2020
b0e78d5
Add default subfolder
eftychis Mar 16, 2020
5620eb5
Merge remote-tracking branch 'origin/master' into eftychis-identity-s…
eftychis Mar 17, 2020
9b7a0eb
Merge remote-tracking branch 'origin/master' into eftychis-identity-s…
eftychis Mar 17, 2020
682b2e4
Rm principal from identity
eftychis Mar 17, 2020
45f1a72
Unupdate
eftychis Mar 18, 2020
5e3c608
Compactify
eftychis Mar 18, 2020
1b2e798
Merge branch 'master' into eftychis-identity-stage1
eftychis Mar 18, 2020
167cbc3
Comment
eftychis Mar 18, 2020
d92b9bb
Fix comment
eftychis Mar 18, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 66 additions & 9 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@ members = [
"src/dfx_derive",
"src/dfx_info",
"src/ic_http_agent",
"src/ic_identity_manager",
"src/serde_idl",
]
1 change: 1 addition & 0 deletions src/dfx/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ flate2 = "1.0.11"
futures = "0.1.28"
hex = "0.3.2"
ic-http-agent = { path = "../ic_http_agent" }
ic-identity-manager = { path = "../ic_identity_manager" }
indicatif = "0.13.0"
lazy-init = "0.3.0"
lazy_static = "1.4.0"
Expand Down
18 changes: 16 additions & 2 deletions src/dfx/src/lib/environment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@ use crate::config::cache::{Cache, DiskBasedCache};
use crate::config::dfinity::Config;
use crate::config::dfx_version;
use crate::lib::error::DfxResult;
use crate::lib::identity_interface::Identity;
use crate::lib::progress_bar::ProgressBar;

use ic_http_agent::{Agent, AgentConfig};
use lazy_init::Lazy;
use semver::Version;
use slog::Record;
use std::fs::create_dir_all;
use std::path::{Path, PathBuf};
use std::rc::Rc;

Expand Down Expand Up @@ -75,7 +77,7 @@ impl EnvironmentImpl {
.into_path(),
Some(c) => c.get_path().parent().unwrap().join(".dfx"),
};
std::fs::create_dir_all(&temp_dir)?;
create_dir_all(&temp_dir)?;

// Figure out which version of DFX we should be running. This will use the following
// fallback sequence:
Expand Down Expand Up @@ -156,9 +158,15 @@ impl Environment for EnvironmentImpl {
let start = config.get_config().get_defaults().get_start();
let address = start.get_address("localhost");
let port = start.get_port(8000);
let dfx_root = self.get_temp_dir();
let local_project_identity = dfx_root.join("identity").join("default");
if create_dir_all(&local_project_identity).is_err() {
return None;
}

Agent::new(AgentConfig {
url: format!("http://{}:{}", address, port).as_str(),
signer: Box::new(Identity::new(local_project_identity)),
..AgentConfig::default()
})
.ok()
Expand Down Expand Up @@ -195,13 +203,19 @@ pub struct AgentEnvironment<'a> {

impl<'a> AgentEnvironment<'a> {
pub fn new(backend: &'a dyn Environment, agent_url: &str) -> Self {
// We do not expose the path directly for now.
let dfx_root = backend.get_temp_dir();
let local_project_identity = dfx_root.join("identity").join("default");
// N.B. Do not assume the existence of this directory yet.
create_dir_all(&local_project_identity).expect("Failed to construct identity profile");
AgentEnvironment {
backend,
agent: Agent::new(AgentConfig {
url: agent_url,
signer: Box::new(Identity::new(local_project_identity)),
..AgentConfig::default()
})
.unwrap(),
.expect("Failed to construct agent"),
}
}
}
Expand Down
75 changes: 75 additions & 0 deletions src/dfx/src/lib/identity_interface.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
use ic_http_agent::to_request_id;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rename this just identity.rs?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually why have this here (I just saw this was in dfx) instead of re-using the ic_identity_manager?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We define the trait in this crate. This would avoid building the whole agent to build the identity crate. And in effect, rebuilding the identity crate every time a small change happens in the agent, which should receive more frequent updates. (I know now types lives under agent, but as suggested and also requested by @chenyan-dfinity, we should have a spec types crate or something along these lines).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Put yourself in someone making a webserver which talks to the IC as a backend (in Rust). They would use ic_http_agent to talk to the IC, but since the IC needs a signature, they'll need to provide a Signer somehow. Should they copy-paste this whole file everywhere, or just use ic_identity_manager?

Alternatively, what's the case for a program that uses ic_identity_manager without using ic_http_agent at all?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In my PR, the separation was clear; ic_pem_identity was for using a PEM (it was an implementation of an identity, with the goal to have maybe ic_yubikey_identity later or similar). The goal was also to reduce transitive dependencies; we don't need to have yubikey-related code if we use pem files.

In this case, I don't know what ic_identity_manager is (still). Is it a manager? Is it the only implementation we'll provide for identity and Signing?

Copy link
Contributor Author

@eftychis eftychis Mar 18, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a lib, it is to be used indirectly. I have gotten a bit mixed messages as to the usage of the agent and its API from the last few discussions, so I stand a bit confused. May I suggest we write down how we want people to use it and define the hierarchy and the pros and cons of each? Rushing ahead a bit, perhaps a thin layer defining an API ahead optimizes for both external users and build times.

I think for now it is fine to optimize for build time and leave the trait implementation there, and then move it in agent_api or something? Or maybe just in the agent. (I think the agent crate as you noted has gotten a bit overloaded, so perhaps clarifying its scope will help. We should think as crates as our compilation, scoping and test buddies.)

ic_identity_manager should house all the implementations, as was mentioned in the documentation in the previous PR, (e.g. like how actix, has multiple actor types). I can run ahead and say we need a common type that deals with multiple principals and associated key pairs and their sources (but I would like to avoid starting this long conversation again). I think it should be the only implementation provided by us at least. (And while someone might decide to write their own agent, they probably should be using our types and identity functionality and not rewrite them. Although I see little point for anyone to rewrite any of the above anytime soon just to say there is a non-dfinity implementation. Thoughts? Perhaps not to be discussed here.) The Signer trait is there to provide separation and mocking ability.

use ic_http_agent::AgentError;
use ic_http_agent::Blob;
use ic_http_agent::RequestId;
use ic_http_agent::SignedMessage;
use ic_http_agent::Signer;
use std::path::PathBuf;

pub struct Identity(ic_identity_manager::Identity);

impl Identity {
/// Construct a new identity handling object, providing given
/// configuration.
pub fn new(identity_config_path: PathBuf) -> Self {
Self(
// We panic as discussed, as that should not be the
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I prefer to avoid comments like this, as they don't age well.

Imagine you join a company, and you see this comment in the code base. Who wrote it? Who discussed it with whom? What is the purpose of this comment?

If this issue matters, then: "TODO(eftychis): Escalate to Dom and return error instead of panic." or whatever, or better still, file a ticket "Return error instead of panic".

If it doesn't matter that much, then omit the comment. It should be clear from the code that it panics, and just as clear that in theory someone could make it return an error instead.

// case. I personally prefer this to be an error.
ic_identity_manager::Identity::new(identity_config_path)
.expect("Expected a valid identity configuration"),
)
}
}

impl Signer for Identity {
fn sign<'a>(
&self,
request: Box<(dyn erased_serde::Serialize + Send + Sync + 'a)>,
) -> Result<
(
RequestId,
Box<dyn erased_serde::Serialize + Send + Sync + 'a>,
),
AgentError,
> {
let request_id = to_request_id(&request).map_err(AgentError::from)?;
let signature_tuple = self
.0
.sign(Blob::from(request_id).as_slice())
.map_err(|e| AgentError::SigningError(e.to_string()))?;
let signature = Blob::from(signature_tuple.signature.clone());
let sender_pubkey = Blob::from(signature_tuple.public_key);
let signed_request = SignedMessage {
request_with_sender: request,
signature,
sender_pubkey,
};
Ok((request_id, Box::new(signed_request)))
}
}

#[cfg(test)]
mod test {
use super::*;
use proptest::prelude::*;
use serde::Serialize;
use tempfile::tempdir;

// Dummy proptest checking request id is correct for now.
proptest! {
#[test]
fn request_id_identity(request: String) {
let dir = tempdir().unwrap();

#[derive(Clone,Serialize)]
struct TestAPI { inner : String}
let request = TestAPI { inner: request};

let request_with_sender = request.clone();
let actual_request_id = to_request_id(&request_with_sender).expect("Failed to produce request id");

let signer = Identity::new(dir.into_path());
let request_id = signer.sign(Box::new(request)).expect("Failed to sign").0;
assert_eq!(request_id, actual_request_id)
}}
}
1 change: 1 addition & 0 deletions src/dfx/src/lib/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
pub mod canister_info;
pub mod environment;
pub mod error;
pub mod identity_interface;
pub mod logger;
pub mod message;
pub mod progress_bar;
Expand Down
2 changes: 2 additions & 0 deletions src/ic_http_agent/src/agent/agent_error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ pub enum AgentError {
ClientError(u16, String),
TimeoutWaitingForResponse,

SigningError(String),

InvalidCborData(serde_cbor::Error),
ReqwestError(reqwest::Error),
SerdeError(SerdeError),
Expand Down
18 changes: 18 additions & 0 deletions src/ic_identity_manager/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
[package]
name = "ic-identity-manager"
version = "0.1.0"
authors = ["DFINITY Stiftung"]
edition = "2018"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
openssl = "0.10.28"
pem = "0.7.0"
ring = "0.16.11"
serde = { version = "1.0", features = ["derive"] }
ic-http-agent = { path = "../ic_http_agent" }


[dev-dependencies]
serde_cbor = "0.10"
Loading