mirror of
https://git.nolog.cz/NoLog.cz/anon.git
synced 2025-01-31 05:03:35 +01:00
add userinfo endpoint
This commit is contained in:
parent
278fc65b2a
commit
e0b571a74a
1 changed files with 71 additions and 11 deletions
82
src/main.rs
82
src/main.rs
|
@ -404,23 +404,27 @@ async fn authenticate_endpoint(mut req: Request<AppState>) -> tide::Result {
|
|||
}
|
||||
}
|
||||
|
||||
// The token is random because there are no resources protected by the token anyway.
|
||||
let mut access_token = [0u8; 32];
|
||||
SystemRandom::new().fill(&mut access_token)?;
|
||||
let access_token = base64_coder::URL_SAFE_NO_PAD.encode(&access_token);
|
||||
let id_token = create_id_token(
|
||||
req.state(),
|
||||
&credentials.0,
|
||||
&code_info.account,
|
||||
code_info.nonce,
|
||||
)?;
|
||||
|
||||
req.state()
|
||||
.successful_logins
|
||||
.fetch_add(1, Ordering::Relaxed);
|
||||
|
||||
// give access code
|
||||
Ok(Response::builder(200).body(json!({
|
||||
"access_token": access_token,
|
||||
"token_type": "Bearer",
|
||||
"expires_in": TOKEN_EXPIRATION,
|
||||
"id_token": create_id_token(req.state(), &credentials.0, &code_info.account, code_info.nonce)?,
|
||||
"scope": "openid profile email"
|
||||
})).into())
|
||||
Ok(Response::builder(200)
|
||||
.body(json!({
|
||||
"access_token": id_token,
|
||||
"token_type": "Bearer",
|
||||
"expires_in": TOKEN_EXPIRATION,
|
||||
"id_token": id_token,
|
||||
"scope": "openid profile email"
|
||||
}))
|
||||
.into())
|
||||
}
|
||||
|
||||
async fn jwks_endpoint(req: Request<AppState>) -> tide::Result {
|
||||
|
@ -445,6 +449,7 @@ async fn configuration_endpoint(req: Request<AppState>) -> tide::Result {
|
|||
"issuer": uri,
|
||||
"authorization_endpoint": uri.join("/authorize")?,
|
||||
"token_endpoint": uri.join("/token")?,
|
||||
"userinfo_endpoint": uri.join("/userinfo")?,
|
||||
"jwks_uri": uri.join("/jwks")?,
|
||||
"response_types_supported": ["code"],
|
||||
"subject_types_supported": ["pairwise"],
|
||||
|
@ -493,6 +498,60 @@ logins_success {}
|
|||
.into())
|
||||
}
|
||||
|
||||
/// We expect the ID token as our access token
|
||||
async fn userinfo_endpoint(req: Request<AppState>) -> tide::Result {
|
||||
// this is all wrapped, because if something fails, then its the
|
||||
// client's fault anyways (if there aren't any bugs, oh well...)
|
||||
let resp = || {
|
||||
let jwt = req
|
||||
.header("Authorization")
|
||||
.and_then(|v| v.get(0).unwrap().as_str().strip_prefix("Bearer "))
|
||||
.ok_or(anyhow!("no bearer token"))?; // extract token
|
||||
|
||||
let (message, signature) = jwt.rsplit_once(".").ok_or(anyhow!("bad token form"))?;
|
||||
|
||||
let pk: ring::rsa::PublicKeyComponents<Vec<u8>> = req.state().signing_key.public().into();
|
||||
|
||||
pk.verify(
|
||||
&ring::signature::RSA_PKCS1_2048_8192_SHA256,
|
||||
message.as_bytes(),
|
||||
&base64_coder::URL_SAFE_NO_PAD.decode(signature)?,
|
||||
)?;
|
||||
|
||||
let (_header, claims) = message.rsplit_once(".").ok_or(anyhow!("bad token form"))?;
|
||||
let decoded_claims = base64_coder::URL_SAFE_NO_PAD.decode(claims)?;
|
||||
let decoded_claims: serde_json::Value = serde_json::from_slice(&decoded_claims)?;
|
||||
|
||||
let now = SystemTime::now()
|
||||
.duration_since(UNIX_EPOCH)
|
||||
.expect("no time travelling allowed before 1970")
|
||||
.as_secs();
|
||||
|
||||
if decoded_claims["exp"]
|
||||
.as_u64()
|
||||
.ok_or(anyhow!("invalid exp"))?
|
||||
< now
|
||||
{
|
||||
Err(anyhow!("token expired"))
|
||||
} else {
|
||||
Ok(Response::builder(200)
|
||||
.content_type("application/json")
|
||||
.body(decoded_claims)
|
||||
.build())
|
||||
}
|
||||
};
|
||||
|
||||
#[allow(unused_variables)] // rustc complains when building in release mode
|
||||
resp().or_else(|e| {
|
||||
#[cfg(debug_assertions)]
|
||||
log::debug!("userinfo error: {}", e);
|
||||
|
||||
Ok(Response::builder(401)
|
||||
.header("WWW-Authenticate", "Bearer error=\"invalid_token\"")
|
||||
.build())
|
||||
})
|
||||
}
|
||||
|
||||
pub struct AuthStore {
|
||||
pub auths: HashMap<String, Authorization>,
|
||||
pub expirations: LinkedList<(String, u64)>,
|
||||
|
@ -563,6 +622,7 @@ async fn main() -> Result<()> {
|
|||
.get(configuration_endpoint);
|
||||
app.at("/new-account").get(create_account_endpoint);
|
||||
app.at("/metrics").get(metrics_endpoint);
|
||||
app.at("/userinfo").get(userinfo_endpoint);
|
||||
|
||||
auto_serve_dir!(app, "/static", "static");
|
||||
|
||||
|
|
Loading…
Reference in a new issue