First complete impl without warns
This commit is contained in:
parent
08d7765644
commit
6b69d34ac8
|
@ -4,7 +4,8 @@ use biscuit::jwk::{AlgorithmParameters, JWKSet};
|
||||||
use biscuit::jws::{Compact, Secret};
|
use biscuit::jws::{Compact, Secret};
|
||||||
use chrono::{Duration, Utc};
|
use chrono::{Duration, Utc};
|
||||||
use inth_oauth2;
|
use inth_oauth2;
|
||||||
use reqwest::{self, Url};
|
use inth_oauth2::token::Token as _t;
|
||||||
|
use reqwest::{self, header, Url};
|
||||||
use url_serde;
|
use url_serde;
|
||||||
use validator::Validate;
|
use validator::Validate;
|
||||||
|
|
||||||
|
@ -12,7 +13,7 @@ use std::collections::HashSet;
|
||||||
|
|
||||||
use discovery::{self, Config, Discovered};
|
use discovery::{self, Config, Discovered};
|
||||||
use error::{self, Decode, Error, Expiry, Mismatch, Missing, Validation};
|
use error::{self, Decode, Error, Expiry, Mismatch, Missing, Validation};
|
||||||
use token::{Claims, Expiring, Token};
|
use token::{Claims, Token};
|
||||||
|
|
||||||
type IdToken = Compact<Claims, Empty>;
|
type IdToken = Compact<Claims, Empty>;
|
||||||
|
|
||||||
|
@ -165,7 +166,7 @@ impl Client {
|
||||||
pub fn request_token(&self,
|
pub fn request_token(&self,
|
||||||
client: &reqwest::Client,
|
client: &reqwest::Client,
|
||||||
auth_code: &str,
|
auth_code: &str,
|
||||||
) -> Result<Token<Expiring>, error::Oauth> {
|
) -> Result<Token, error::Oauth> {
|
||||||
self.oauth.request_token(client, auth_code)
|
self.oauth.request_token(client, auth_code)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -218,7 +219,7 @@ impl Client {
|
||||||
|
|
||||||
/// Given an auth_code and auth options, request the token, decode, and validate it.
|
/// Given an auth_code and auth options, request the token, decode, and validate it.
|
||||||
pub fn authenticate(&self, auth_code: &str, options: &Options
|
pub fn authenticate(&self, auth_code: &str, options: &Options
|
||||||
) -> Result<Token<Expiring>, Error> {
|
) -> Result<Token, Error> {
|
||||||
let client = reqwest::Client::new()?;
|
let client = reqwest::Client::new()?;
|
||||||
let mut token = self.request_token(&client, auth_code)?;
|
let mut token = self.request_token(&client, auth_code)?;
|
||||||
self.decode_token(&mut token.id_token)?;
|
self.decode_token(&mut token.id_token)?;
|
||||||
|
@ -347,13 +348,22 @@ impl Client {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn request_userinfo(&self, client: &reqwest::Client, token: &Token<Expiring>) -> Result<Userinfo, Error> {
|
pub fn request_userinfo(&self, client: &reqwest::Client, token: &Token) -> Result<Userinfo, Error> {
|
||||||
match self.config().userinfo_endpoint {
|
match self.config().userinfo_endpoint {
|
||||||
Some(ref url) => {
|
Some(ref url) => {
|
||||||
|
discovery::secure(&url)?;
|
||||||
if url.origin() != self.config().issuer.origin() {
|
if url.origin() != self.config().issuer.origin() {
|
||||||
return Err(error::Userinfo::MismatchIssuer.into());
|
return Err(error::Userinfo::MismatchIssuer.into());
|
||||||
}
|
}
|
||||||
unimplemented!()
|
let claims = token.id_token.payload()?;
|
||||||
|
let auth_code = token.access_token().to_string();
|
||||||
|
let mut resp = client.get(url.clone())?
|
||||||
|
.header(header::Authorization(header::Bearer { token: auth_code })).send()?;
|
||||||
|
let info: Userinfo = resp.json()?;
|
||||||
|
if claims.sub != info.sub {
|
||||||
|
return Err(error::Userinfo::MismatchSubject.into())
|
||||||
|
}
|
||||||
|
Ok(info)
|
||||||
}
|
}
|
||||||
None => Err(error::Userinfo::NoUrl.into())
|
None => Err(error::Userinfo::NoUrl.into())
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,21 @@
|
||||||
use biscuit::Empty;
|
use biscuit::Empty;
|
||||||
use biscuit::jwk::JWKSet;
|
use biscuit::jwk::JWKSet;
|
||||||
use inth_oauth2::provider::Provider;
|
use inth_oauth2::provider::Provider;
|
||||||
|
use inth_oauth2::token::Expiring;
|
||||||
use reqwest::{Client, Url};
|
use reqwest::{Client, Url};
|
||||||
use url_serde;
|
use url_serde;
|
||||||
use validator::Validate;
|
use validator::Validate;
|
||||||
|
|
||||||
use error::Error;
|
use error::Error;
|
||||||
use token::{Expiring, Token};
|
use token::Token;
|
||||||
|
|
||||||
|
pub(crate) fn secure(url: &Url) -> Result<(), Error> {
|
||||||
|
if url.scheme() != "https" {
|
||||||
|
Err(Error::Insecure)
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize)]
|
#[derive(Deserialize, Serialize)]
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
|
@ -114,7 +123,7 @@ pub struct Discovered {
|
||||||
|
|
||||||
impl Provider for Discovered {
|
impl Provider for Discovered {
|
||||||
type Lifetime = Expiring;
|
type Lifetime = Expiring;
|
||||||
type Token = Token<Expiring>;
|
type Token = Token;
|
||||||
fn auth_uri(&self) -> &str {
|
fn auth_uri(&self) -> &str {
|
||||||
self.config.authorization_endpoint.as_ref()
|
self.config.authorization_endpoint.as_ref()
|
||||||
}
|
}
|
||||||
|
@ -127,10 +136,7 @@ impl Provider for Discovered {
|
||||||
/// Get the discovery config document from the given issuer url. Errors are either a reqwest error
|
/// Get the discovery config document from the given issuer url. Errors are either a reqwest error
|
||||||
/// or an Insecure if the Url isn't https.
|
/// or an Insecure if the Url isn't https.
|
||||||
pub fn discover(client: &Client, issuer: Url) -> Result<Config, Error> {
|
pub fn discover(client: &Client, issuer: Url) -> Result<Config, Error> {
|
||||||
if issuer.scheme() != "https" {
|
secure(&issuer)?;
|
||||||
return Err(Error::Insecure)
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut resp = client.get(issuer)?.send()?;
|
let mut resp = client.get(issuer)?.send()?;
|
||||||
resp.json().map_err(Error::from)
|
resp.json().map_err(Error::from)
|
||||||
}
|
}
|
||||||
|
@ -138,10 +144,7 @@ pub fn discover(client: &Client, issuer: Url) -> Result<Config, Error> {
|
||||||
/// Get the JWK set from the given Url. Errors are either a reqwest error or an Insecure error if
|
/// Get the JWK set from the given Url. Errors are either a reqwest error or an Insecure error if
|
||||||
/// the url isn't https.
|
/// the url isn't https.
|
||||||
pub fn jwks(client: &Client, url: Url) -> Result<JWKSet<Empty>, Error> {
|
pub fn jwks(client: &Client, url: Url) -> Result<JWKSet<Empty>, Error> {
|
||||||
if url.scheme() != "https" {
|
secure(&url)?;
|
||||||
return Err(Error::Insecure)
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut resp = client.get(url)?.send()?;
|
let mut resp = client.get(url)?.send()?;
|
||||||
resp.json().map_err(Error::from)
|
resp.json().map_err(Error::from)
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,6 +71,6 @@ pub enum Expiry {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Userinfo {
|
pub enum Userinfo {
|
||||||
NoUrl,
|
NoUrl,
|
||||||
|
MismatchIssuer,
|
||||||
MismatchSubject,
|
MismatchSubject,
|
||||||
|
|
||||||
}
|
}
|
|
@ -3,6 +3,8 @@ extern crate biscuit;
|
||||||
extern crate chrono;
|
extern crate chrono;
|
||||||
extern crate inth_oauth2;
|
extern crate inth_oauth2;
|
||||||
extern crate reqwest;
|
extern crate reqwest;
|
||||||
|
// We never use serde, but serde_derive needs it here
|
||||||
|
#[allow(unused_extern_crates)]
|
||||||
extern crate serde;
|
extern crate serde;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate serde_derive;
|
extern crate serde_derive;
|
||||||
|
|
17
src/token.rs
17
src/token.rs
|
@ -2,14 +2,11 @@ use base64;
|
||||||
use biscuit::{CompactJson, Empty, SingleOrMultiple};
|
use biscuit::{CompactJson, Empty, SingleOrMultiple};
|
||||||
use biscuit::jws::Compact;
|
use biscuit::jws::Compact;
|
||||||
use inth_oauth2::client::response::{FromResponse, ParseError};
|
use inth_oauth2::client::response::{FromResponse, ParseError};
|
||||||
use inth_oauth2::token::{self, Bearer, Lifetime};
|
use inth_oauth2::token::{self, Bearer, Expiring};
|
||||||
use reqwest::Url;
|
use reqwest::Url;
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
use url_serde;
|
use url_serde;
|
||||||
|
|
||||||
/// Rexported lifetime token types from oauth
|
|
||||||
pub use inth_oauth2::token::{Expiring, Refresh, Static};
|
|
||||||
|
|
||||||
type IdToken = Compact<Claims, Empty>;
|
type IdToken = Compact<Claims, Empty>;
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
|
@ -60,12 +57,12 @@ impl CompactJson for Claims {}
|
||||||
/// An OpenID Connect token. This is the only token allowed by spec.
|
/// An OpenID Connect token. This is the only token allowed by spec.
|
||||||
/// Has an access_token for bearer, and the id_token for authentication.
|
/// Has an access_token for bearer, and the id_token for authentication.
|
||||||
/// Wraps an oauth bearer token.
|
/// Wraps an oauth bearer token.
|
||||||
pub struct Token<L: Lifetime> {
|
pub struct Token {
|
||||||
bearer: Bearer<L>,
|
bearer: Bearer<Expiring>,
|
||||||
pub id_token: IdToken,
|
pub id_token: IdToken,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<L: Lifetime> Token<L> {
|
impl Token {
|
||||||
// Takes a json response object and parses out the id token
|
// Takes a json response object and parses out the id token
|
||||||
// TODO Support extracting a jwe token according to spec. Right now we only support jws tokens.
|
// TODO Support extracting a jwe token according to spec. Right now we only support jws tokens.
|
||||||
fn id_token(json: &Value) -> Result<IdToken, ParseError> {
|
fn id_token(json: &Value) -> Result<IdToken, ParseError> {
|
||||||
|
@ -77,19 +74,19 @@ impl<L: Lifetime> Token<L> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<L: Lifetime> token::Token<L> for Token<L> {
|
impl token::Token<Expiring> for Token {
|
||||||
fn access_token(&self) -> &str {
|
fn access_token(&self) -> &str {
|
||||||
self.bearer.access_token()
|
self.bearer.access_token()
|
||||||
}
|
}
|
||||||
fn scope(&self) -> Option<&str> {
|
fn scope(&self) -> Option<&str> {
|
||||||
self.bearer.scope()
|
self.bearer.scope()
|
||||||
}
|
}
|
||||||
fn lifetime(&self) -> &L {
|
fn lifetime(&self) -> &Expiring {
|
||||||
self.bearer.lifetime()
|
self.bearer.lifetime()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<L: Lifetime> FromResponse for Token<L> {
|
impl FromResponse for Token {
|
||||||
fn from_response(json: &Value) -> Result<Self, ParseError> {
|
fn from_response(json: &Value) -> Result<Self, ParseError> {
|
||||||
let bearer = Bearer::from_response(json)?;
|
let bearer = Bearer::from_response(json)?;
|
||||||
let id_token = Self::id_token(json)?;
|
let id_token = Self::id_token(json)?;
|
||||||
|
|
Loading…
Reference in New Issue