Add c_hash, at_hash and nonce claims to id_token

This commit is contained in:
Quentin Gliech
2021-09-09 16:52:08 +02:00
parent 909da01918
commit 81d95ef215
5 changed files with 48 additions and 18 deletions

1
Cargo.lock generated
View File

@@ -1405,6 +1405,7 @@ dependencies = [
"serde_urlencoded",
"serde_with",
"serde_yaml",
"sha2",
"sqlx",
"tera",
"thiserror",

View File

@@ -49,12 +49,14 @@ dotenv = "0.15.0"
argon2 = { version = "0.3.0", features = ["password-hash"] }
password-hash = { version = "0.3.0", features = ["std"] }
# Crypto and signing stuff
# Crypto, hashing and signing stuff
rsa = "0.5.0"
k256 = "0.9.6"
pkcs8 = { version = "0.7.5", features = ["pem"] }
elliptic-curve = { version = "0.10.6", features = ["pem"] }
chacha20poly1305 = { version = "0.9.0", features = ["std"] }
sha2 = "0.9.8"
crc = "2.0.0"
# Various data types and utilities
data-encoding = "2.3.2"
@@ -66,7 +68,6 @@ rand = "0.8.4"
bincode = "1.3.3"
headers = "0.3.4"
cookie = "0.15.1"
crc = "2.0.0"
oauth2-types = { path = "../oauth2-types", features = ["sqlx_type"] }

View File

@@ -381,20 +381,8 @@
]
}
},
"88ac8783bd5881c42eafd9cf87a16fe6031f3153fd6a8618e689694584aeb2de": {
"query": "\n DELETE FROM oauth2_access_tokens\n WHERE id = $1\n ",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Int8"
]
},
"nullable": []
}
},
"8c21b0b46e74ae5667b82bfe57706a64396683ac4dc29311424008c3f3e94136": {
"query": "\n SELECT\n oc.id,\n os.id AS \"oauth2_session_id!\",\n os.client_id AS \"client_id!\",\n os.redirect_uri,\n os.scope AS \"scope!\"\n FROM oauth2_codes oc\n INNER JOIN oauth2_sessions os\n ON os.id = oc.oauth2_session_id\n WHERE oc.code = $1\n ",
"886dee6a6f1f426f0e891790bbeffbc222fd75d8da0a107e7de673f1cc445f30": {
"query": "\n SELECT\n oc.id,\n os.id AS \"oauth2_session_id!\",\n os.client_id AS \"client_id!\",\n os.redirect_uri,\n os.scope AS \"scope!\",\n os.nonce\n FROM oauth2_codes oc\n INNER JOIN oauth2_sessions os\n ON os.id = oc.oauth2_session_id\n WHERE oc.code = $1\n ",
"describe": {
"columns": [
{
@@ -421,6 +409,11 @@
"ordinal": 4,
"name": "scope!",
"type_info": "Text"
},
{
"ordinal": 5,
"name": "nonce",
"type_info": "Text"
}
],
"parameters": {
@@ -433,10 +426,23 @@
false,
false,
false,
false
false,
true
]
}
},
"88ac8783bd5881c42eafd9cf87a16fe6031f3153fd6a8618e689694584aeb2de": {
"query": "\n DELETE FROM oauth2_access_tokens\n WHERE id = $1\n ",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Int8"
]
},
"nullable": []
}
},
"9ba45ab114b656105cc46b0c10fb05769860fcdc05eaf54d6225640fb914dab9": {
"query": "\n INSERT INTO user_session_authentications (session_id)\n VALUES ($1)\n RETURNING created_at\n ",
"describe": {

View File

@@ -14,6 +14,7 @@
use anyhow::Context;
use chrono::Duration;
use data_encoding::BASE64URL_NOPAD;
use jwt_compact::{Claims, Header, TimeOptions};
use oauth2_types::{
errors::{InvalidGrant, OAuth2Error},
@@ -23,6 +24,8 @@ use oauth2_types::{
};
use rand::thread_rng;
use serde::Serialize;
use serde_with::skip_serializing_none;
use sha2::{Digest, Sha256};
use sqlx::{pool::PoolConnection, Acquire, PgPool, Postgres};
use url::Url;
use warp::{Filter, Rejection, Reply};
@@ -43,6 +46,7 @@ use crate::{
tokens,
};
#[skip_serializing_none]
#[derive(Serialize, Debug)]
struct CustomClaims {
#[serde(rename = "iss")]
@@ -51,6 +55,9 @@ struct CustomClaims {
subject: String,
#[serde(rename = "aud")]
audiences: Vec<String>,
nonce: Option<String>,
at_hash: String,
c_hash: String,
}
pub fn filter(
@@ -93,6 +100,16 @@ async fn token(
Ok(reply)
}
fn hash<H: Digest>(mut hasher: H, token: &str) -> anyhow::Result<String> {
hasher.update(token);
let hash = hasher.finalize();
// Left-most 128bit
let bits = hash
.get(..16)
.context("failed to get first 128 bits of hash")?;
Ok(BASE64URL_NOPAD.encode(bits))
}
async fn authorization_code_grant(
grant: &AuthorizationCodeGrant,
client: &OAuth2ClientConfig,
@@ -138,6 +155,9 @@ async fn authorization_code_grant(
// TODO: get that from the session
subject: "random-subject".to_string(),
audiences: vec![client.client_id.clone()],
nonce: code.nonce,
at_hash: hash(Sha256::new(), &access_token.token).wrap_error()?,
c_hash: hash(Sha256::new(), &grant.code).wrap_error()?,
})
.set_duration_and_issuance(&options, Duration::minutes(30));
let id_token = keys

View File

@@ -62,6 +62,7 @@ pub struct OAuth2CodeLookup {
pub client_id: String,
pub redirect_uri: String,
pub scope: String,
pub nonce: Option<String>,
}
pub async fn lookup_code(
@@ -76,7 +77,8 @@ pub async fn lookup_code(
os.id AS "oauth2_session_id!",
os.client_id AS "client_id!",
os.redirect_uri,
os.scope AS "scope!"
os.scope AS "scope!",
os.nonce
FROM oauth2_codes oc
INNER JOIN oauth2_sessions os
ON os.id = oc.oauth2_session_id