mod authorization;
mod accesstoken;
mod client_credentials;
mod error;
mod refresh;
mod resource;
mod query;
#[cfg(test)]
mod tests;
use std::borrow::Cow;
use std::marker::PhantomData;
pub use crate::primitives::authorizer::Authorizer;
pub use crate::primitives::issuer::Issuer;
pub use crate::primitives::registrar::Registrar;
pub use crate::primitives::scope::Scope;
use crate::code_grant::resource::{Error as ResourceError};
use crate::code_grant::error::{AuthorizationError, AccessTokenError};
use url::Url;
pub use crate::code_grant::authorization::Extension as AuthorizationExtension;
pub use crate::code_grant::accesstoken::Extension as AccessTokenExtension;
pub use crate::code_grant::client_credentials::Extension as ClientCredentialsExtension;
pub use crate::primitives::registrar::PreGrant;
pub use self::authorization::*;
pub use self::accesstoken::*;
pub use self::client_credentials::ClientCredentialsFlow;
pub use self::error::OAuthError;
pub use self::refresh::RefreshFlow;
pub use self::resource::*;
pub use self::query::*;
pub enum OwnerConsent<Response: WebResponse> {
Denied,
InProgress(Response),
Authorized(String),
Error(Response::Error),
}
#[derive(Debug)]
pub struct Template<'a> {
inner: InnerTemplate<'a>,
}
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub enum ResponseStatus {
Unauthorized,
Redirect,
BadRequest,
Ok,
}
#[derive(Debug)]
#[non_exhaustive]
enum InnerTemplate<'a> {
Unauthorized {
#[allow(dead_code)]
error: Option<ResourceError>,
access_token_error: Option<&'a mut AccessTokenError>,
},
Redirect {
authorization_error: Option<&'a mut AuthorizationError>,
},
BadRequest {
access_token_error: Option<&'a mut AccessTokenError>,
},
Ok,
}
pub struct Solicitation<'flow> {
pub(crate) grant: Cow<'flow, PreGrant>,
pub(crate) state: Option<Cow<'flow, str>>,
}
impl<'flow> Solicitation<'flow> {
pub fn into_owned(self) -> Solicitation<'static> {
Solicitation {
grant: Cow::Owned(self.grant.into_owned()),
state: self.state.map(|state| Cow::Owned(state.into_owned())),
}
}
pub fn pre_grant(&self) -> &PreGrant {
self.grant.as_ref()
}
pub fn state(&self) -> Option<&str> {
match self.state {
None => None,
Some(ref state) => Some(&state),
}
}
pub fn new(grant: &'flow PreGrant) -> Self {
Solicitation {
grant: Cow::Borrowed(grant),
state: None,
}
}
pub fn with_state(self, state: &'flow str) -> Self {
Solicitation {
state: Some(Cow::Borrowed(state)),
..self
}
}
}
pub trait OwnerSolicitor<Request: WebRequest> {
fn check_consent(&mut self, _: &mut Request, _: Solicitation) -> OwnerConsent<Request::Response>;
}
pub trait Scopes<Request: WebRequest> {
fn scopes(&mut self, request: &mut Request) -> &[Scope];
}
pub trait WebRequest {
type Error;
type Response: WebResponse<Error = Self::Error>;
fn query(&mut self) -> Result<Cow<dyn QueryParameter + 'static>, Self::Error>;
fn urlbody(&mut self) -> Result<Cow<dyn QueryParameter + 'static>, Self::Error>;
fn authheader(&mut self) -> Result<Option<Cow<str>>, Self::Error>;
}
pub trait WebResponse {
type Error;
fn ok(&mut self) -> Result<(), Self::Error>;
fn redirect(&mut self, url: Url) -> Result<(), Self::Error>;
fn client_error(&mut self) -> Result<(), Self::Error>;
fn unauthorized(&mut self, header_value: &str) -> Result<(), Self::Error>;
fn body_text(&mut self, text: &str) -> Result<(), Self::Error>;
fn body_json(&mut self, data: &str) -> Result<(), Self::Error>;
}
pub trait Extension {
fn authorization(&mut self) -> Option<&mut dyn AuthorizationExtension> {
None
}
fn access_token(&mut self) -> Option<&mut dyn AccessTokenExtension> {
None
}
fn client_credentials(&mut self) -> Option<&mut dyn ClientCredentialsExtension> {
None
}
}
pub trait Endpoint<Request: WebRequest> {
type Error;
fn registrar(&self) -> Option<&dyn Registrar>;
fn authorizer_mut(&mut self) -> Option<&mut dyn Authorizer>;
fn issuer_mut(&mut self) -> Option<&mut dyn Issuer>;
fn owner_solicitor(&mut self) -> Option<&mut dyn OwnerSolicitor<Request>>;
fn scopes(&mut self) -> Option<&mut dyn Scopes<Request>>;
fn response(
&mut self, request: &mut Request, kind: Template,
) -> Result<Request::Response, Self::Error>;
fn error(&mut self, err: OAuthError) -> Self::Error;
fn web_error(&mut self, err: Request::Error) -> Self::Error;
fn extension(&mut self) -> Option<&mut dyn Extension> {
None
}
}
impl<'a> Template<'a> {
pub fn new_ok() -> Self {
InnerTemplate::Ok.into()
}
pub fn new_bad(access_token_error: Option<&'a mut AccessTokenError>) -> Self {
InnerTemplate::BadRequest { access_token_error }.into()
}
pub fn new_unauthorized(
error: Option<ResourceError>, access_token_error: Option<&'a mut AccessTokenError>,
) -> Self {
InnerTemplate::Unauthorized {
error,
access_token_error,
}
.into()
}
pub fn new_redirect(authorization_error: Option<&'a mut AuthorizationError>) -> Self {
InnerTemplate::Redirect { authorization_error }.into()
}
pub fn status(&self) -> ResponseStatus {
match self.inner {
InnerTemplate::Unauthorized { .. } => ResponseStatus::Unauthorized,
InnerTemplate::Redirect { .. } => ResponseStatus::Redirect,
InnerTemplate::BadRequest { .. } => ResponseStatus::BadRequest,
InnerTemplate::Ok => ResponseStatus::Ok,
}
}
pub fn authorization_error(&mut self) -> Option<&mut AuthorizationError> {
match &mut self.inner {
InnerTemplate::Redirect {
authorization_error, ..
} => reborrow(authorization_error),
_ => None,
}
}
pub fn access_token_error(&mut self) -> Option<&mut AccessTokenError> {
match &mut self.inner {
InnerTemplate::Unauthorized {
access_token_error, ..
} => reborrow(access_token_error),
InnerTemplate::BadRequest {
access_token_error, ..
} => reborrow(access_token_error),
_ => None,
}
}
}
fn reborrow<'a, T>(opt: &'a mut Option<&mut T>) -> Option<&'a mut T> {
match opt {
Some(inner) => Some(inner),
None => None,
}
}
impl<'a, W: WebRequest> WebRequest for &'a mut W {
type Error = W::Error;
type Response = W::Response;
fn query(&mut self) -> Result<Cow<dyn QueryParameter + 'static>, Self::Error> {
(**self).query()
}
fn urlbody(&mut self) -> Result<Cow<dyn QueryParameter + 'static>, Self::Error> {
(**self).urlbody()
}
fn authheader(&mut self) -> Result<Option<Cow<str>>, Self::Error> {
(**self).authheader()
}
}
impl<'a, R: WebRequest, E: Endpoint<R>> Endpoint<R> for &'a mut E {
type Error = E::Error;
fn registrar(&self) -> Option<&dyn Registrar> {
(**self).registrar()
}
fn authorizer_mut(&mut self) -> Option<&mut dyn Authorizer> {
(**self).authorizer_mut()
}
fn issuer_mut(&mut self) -> Option<&mut dyn Issuer> {
(**self).issuer_mut()
}
fn owner_solicitor(&mut self) -> Option<&mut dyn OwnerSolicitor<R>> {
(**self).owner_solicitor()
}
fn scopes(&mut self) -> Option<&mut dyn Scopes<R>> {
(**self).scopes()
}
fn response(&mut self, request: &mut R, kind: Template) -> Result<R::Response, Self::Error> {
(**self).response(request, kind)
}
fn error(&mut self, err: OAuthError) -> Self::Error {
(**self).error(err)
}
fn web_error(&mut self, err: R::Error) -> Self::Error {
(**self).web_error(err)
}
fn extension(&mut self) -> Option<&mut dyn Extension> {
(**self).extension()
}
}
impl<'a, R: WebRequest, E: Endpoint<R> + 'a> Endpoint<R> for Box<E> {
type Error = E::Error;
fn registrar(&self) -> Option<&dyn Registrar> {
(**self).registrar()
}
fn authorizer_mut(&mut self) -> Option<&mut dyn Authorizer> {
(**self).authorizer_mut()
}
fn issuer_mut(&mut self) -> Option<&mut dyn Issuer> {
(**self).issuer_mut()
}
fn owner_solicitor(&mut self) -> Option<&mut dyn OwnerSolicitor<R>> {
(**self).owner_solicitor()
}
fn scopes(&mut self) -> Option<&mut dyn Scopes<R>> {
(**self).scopes()
}
fn response(&mut self, request: &mut R, kind: Template) -> Result<R::Response, Self::Error> {
(**self).response(request, kind)
}
fn error(&mut self, err: OAuthError) -> Self::Error {
(**self).error(err)
}
fn web_error(&mut self, err: R::Error) -> Self::Error {
(**self).web_error(err)
}
fn extension(&mut self) -> Option<&mut dyn Extension> {
(**self).extension()
}
}
impl Extension for () {}
impl<'a, W: WebRequest, S: OwnerSolicitor<W> + 'a + ?Sized> OwnerSolicitor<W> for &'a mut S {
fn check_consent(
&mut self, request: &mut W, solicitation: Solicitation,
) -> OwnerConsent<W::Response> {
(**self).check_consent(request, solicitation)
}
}
impl<'a, W: WebRequest, S: OwnerSolicitor<W> + 'a + ?Sized> OwnerSolicitor<W> for Box<S> {
fn check_consent(
&mut self, request: &mut W, solicitation: Solicitation,
) -> OwnerConsent<W::Response> {
(**self).check_consent(request, solicitation)
}
}
impl<W: WebRequest> Scopes<W> for [Scope] {
fn scopes(&mut self, _: &mut W) -> &[Scope] {
self
}
}
impl<W: WebRequest> Scopes<W> for Vec<Scope> {
fn scopes(&mut self, _: &mut W) -> &[Scope] {
self.as_slice()
}
}
impl<'a, W: WebRequest> Scopes<W> for &'a [Scope] {
fn scopes(&mut self, _: &mut W) -> &[Scope] {
self
}
}
impl<'a, W: WebRequest, S: Scopes<W> + 'a + ?Sized> Scopes<W> for &'a mut S {
fn scopes(&mut self, request: &mut W) -> &[Scope] {
(**self).scopes(request)
}
}
impl<'a, W: WebRequest, S: Scopes<W> + 'a + ?Sized> Scopes<W> for Box<S> {
fn scopes(&mut self, request: &mut W) -> &[Scope] {
(**self).scopes(request)
}
}
impl<'a> From<InnerTemplate<'a>> for Template<'a> {
fn from(inner: InnerTemplate<'a>) -> Self {
Template { inner }
}
}
pub fn is_authorization_method<'h>(header: &'h str, method: &'static str) -> Option<&'h str> {
let header_method = header.get(..method.len())?;
if header_method.eq_ignore_ascii_case(method) {
Some(&header[method.len()..])
} else {
None
}
}