Skip to content

Commit

Permalink
Implement Google JWT verification and build time environment variables.
Browse files Browse the repository at this point in the history
  • Loading branch information
sea-snake committed Jan 13, 2025
1 parent f773987 commit 7ab4c76
Show file tree
Hide file tree
Showing 12 changed files with 476 additions and 13 deletions.
80 changes: 80 additions & 0 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 @@ -48,3 +48,4 @@ serde = "1"
serde_bytes = "0.11"
serde_cbor = "0.11"
sha2 = "0.10"
rsa = "0.9.7"
1 change: 1 addition & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ ARG II_FETCH_ROOT_KEY=
ARG II_DUMMY_CAPTCHA=
ARG II_DUMMY_AUTH=
ARG II_DEV_CSP=
ARG II_OPENID_GOOGLE_CLIENT_ID=

RUN touch src/*/src/lib.rs
RUN npm ci
Expand Down
6 changes: 3 additions & 3 deletions dfx.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
"type": "custom",
"candid": "src/internet_identity/internet_identity.did",
"wasm": "internet_identity.wasm.gz",
"build": "bash -c 'II_DEV_CSP=1 II_FETCH_ROOT_KEY=1 II_DUMMY_CAPTCHA=${II_DUMMY_CAPTCHA:-1} scripts/build'",
"build": "bash -c 'II_DEV_CSP=1 II_FETCH_ROOT_KEY=1 II_DUMMY_CAPTCHA=${II_DUMMY_CAPTCHA:-1} II_OPENID_GOOGLE_CLIENT_ID=\"45431994619-cbbfgtn7o0pp0dpfcg2l66bc4rcg7qbu.apps.googleusercontent.com\" scripts/build'",
"init_arg": "(opt record { captcha_config = opt record { max_unsolved_captchas= 50:nat64; captcha_trigger = variant {Static = variant {CaptchaDisabled}}}})",
"shrink" : false
"shrink": false
},
"test_app": {
"type": "custom",
Expand All @@ -20,7 +20,7 @@
"wasm": "demos/vc_issuer/vc_demo_issuer.wasm.gz",
"build": "demos/vc_issuer/build.sh",
"post_install": "bash -c 'demos/vc_issuer/provision'",
"dependencies": [ "internet_identity" ]
"dependencies": ["internet_identity"]
}
},
"defaults": {
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
"private": true,
"license": "SEE LICENSE IN LICENSE.md",
"scripts": {
"dev": "II_FETCH_ROOT_KEY=1 II_DUMMY_CAPTCHA=1 II_OPENID_GOOGLE_CLIENT_ID=45431994619-cbbfgtn7o0pp0dpfcg2l66bc4rcg7qbu.apps.googleusercontent.com vite",
"host": "II_FETCH_ROOT_KEY=1 II_DUMMY_CAPTCHA=1 II_OPENID_GOOGLE_CLIENT_ID=45431994619-cbbfgtn7o0pp0dpfcg2l66bc4rcg7qbu.apps.googleusercontent.com vite --host",
"dev": "II_FETCH_ROOT_KEY=1 II_DUMMY_CAPTCHA=1 II_OPENID_GOOGLE_CLIENT_ID=\"45431994619-cbbfgtn7o0pp0dpfcg2l66bc4rcg7qbu.apps.googleusercontent.com\" vite",
"host": "II_FETCH_ROOT_KEY=1 II_DUMMY_CAPTCHA=1 II_OPENID_GOOGLE_CLIENT_ID=\"45431994619-cbbfgtn7o0pp0dpfcg2l66bc4rcg7qbu.apps.googleusercontent.com\" vite --host",
"showcase": "astro dev --root ./src/showcase",
"build": "tsc --noEmit && vite build",
"check": "tsc --project ./tsconfig.all.json --noEmit",
Expand Down
2 changes: 1 addition & 1 deletion scripts/build
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ function build_canister() {
echo Running cargo build "${cargo_build_args[@]}"
echo RUSTFLAGS: "$RUSTFLAGS"

RUSTFLAGS="$RUSTFLAGS" cargo build "${cargo_build_args[@]}"
II_OPENID_GOOGLE_CLIENT_ID="$II_OPENID_GOOGLE_CLIENT_ID" RUSTFLAGS="$RUSTFLAGS" cargo build "${cargo_build_args[@]}"

if [ "$ONLY_DEPS" != "1" ]
then
Expand Down
3 changes: 2 additions & 1 deletion src/internet_identity/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@ serde.workspace = true
serde_bytes.workspace = true
serde_cbor.workspace = true
serde_json = { version = "1.0", default-features = false, features = ["std"] }
sha2.workspace = true
sha2 = { workspace = true, features = ["oid"]}
base64.workspace = true
rsa.workspace = true

# Captcha deps
lodepng = "*"
Expand Down
17 changes: 17 additions & 0 deletions src/internet_identity/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
use std::path::Path;
use std::{env, fs};

// OpenID Google client id used by tests
const TEST_OPENID_GOOGLE_CLIENT_ID: &str =
"45431994619-cbbfgtn7o0pp0dpfcg2l66bc4rcg7qbu.apps.googleusercontent.com";

// Write environment variables to constants during build time
fn main() {
let openid_google_client_id =
env::var("II_OPENID_GOOGLE_CLIENT_ID").unwrap_or(TEST_OPENID_GOOGLE_CLIENT_ID.into());
fs::write(
Path::new(&env::var("OUT_DIR").unwrap()).join("constants.rs"),
format!("pub const OPENID_GOOGLE_CLIENT_ID: &str = \"{openid_google_client_id}\";"),
)
.unwrap();
}
2 changes: 2 additions & 0 deletions src/internet_identity/src/constants.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// Include the generated constants.rs file
include!(concat!(env!("OUT_DIR"), "/constants.rs"));
1 change: 1 addition & 0 deletions src/internet_identity/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ mod state;
mod stats;
mod storage;
mod vc_mvp;
mod constants;

// Some time helpers
const fn secs_to_nanos(secs: u64) -> u64 {
Expand Down
38 changes: 38 additions & 0 deletions src/internet_identity/src/openid.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,43 @@
use candid::{Deserialize, Principal};
use identity_jose::jws::Decoder;
use internet_identity_interface::internet_identity::types::{MetadataEntryV2, Timestamp};
use std::collections::HashMap;

mod google;

#[derive(Debug, PartialEq)]
pub struct OpenIdCredential {
pub iss: String,
pub sub: String,
pub aud: String,
pub principal: Principal,
pub last_usage_timestamp: Timestamp,
pub metadata: HashMap<String, MetadataEntryV2>,
}

#[derive(Deserialize)]
struct PartialClaims {
iss: String,
}

pub fn setup_timers() {
google::setup_timers();
}

#[allow(unused)]
pub fn verify(
jwt: &str,
session_principal: &Principal,
session_salt: &[u8; 32],
timestamp: Timestamp,
) -> Result<OpenIdCredential, String> {
let validation_item = Decoder::new()
.decode_compact_serialization(jwt.as_bytes(), None)
.map_err(|_| "Failed to decode JWT")?;
let claims: PartialClaims =
serde_json::from_slice(validation_item.claims()).map_err(|_| "Unable to decode claims")?;
match claims.iss.as_str() {
google::ISSUER => google::verify(jwt, session_principal, session_salt, timestamp),
_ => Err(format!("Unsupported issuer: {}", claims.iss)),
}
}
Loading

0 comments on commit 7ab4c76

Please sign in to comment.