oxide_auth/endpoint/
mod.rs

1//! Polymorphic HTTP wrappers for code grant authorization and other flows.
2//!
3//! An endpoint is concerned with executing the abstract behaviours given by the backend in terms
4//! of the actions of the endpoint types. This means translating Redirect errors to the correct
5//! Redirect http response for example or optionally sending internal errors to loggers. The
6//! frontends, which are the bindings to particular server libraries, can instantiate the endpoint
7//! api or simple reuse existing types.
8//!
9//! To ensure the adherence to the oauth2 rfc and the improve general implementations, some control
10//! flow of incoming packets is specified here instead of the frontend implementations.  Instead,
11//! traits are offered to make this compatible with other endpoints. In theory, this makes
12//! endpoints pluggable which could improve testing.
13//!
14//! Custom endpoint
15//! ---------------
16//! In order to not place restrictions on the web server library in use, it is possible to
17//! implement an endpoint completely with user defined types.
18//!
19//! This requires custom, related implementations of [`WebRequest`] and [`WebResponse`].
20//! _WARNING_: Custom endpoints MUST ensure a secure communication layer with confidential clients.
21//! This means using TLS for communication over https.
22//!
23//! After receiving an authorization grant, access token or access request, initiate the respective
24//! flow by collecting the [`Authorizer`], [`Issuer`], and [`Registrar`] instances. For example:
25//!
26//! [`WebRequest`]: trait.WebRequest.html
27//! [`WebResponse`]: trait.WebResponse.html
28//! [`Authorizer`]: ../../primitives/authorizer/trait.Authorizer.html
29//! [`Issuer`]: ../../primitives/issuer/trait.Issuer.html
30//! [`Registrar`]: ../../primitives/registrar/trait.Registrar.html
31mod authorization;
32mod accesstoken;
33mod client_credentials;
34mod error;
35mod refresh;
36mod resource;
37mod query;
38
39#[cfg(test)]
40mod tests;
41
42use std::borrow::Cow;
43use std::marker::PhantomData;
44
45pub use crate::primitives::authorizer::Authorizer;
46pub use crate::primitives::issuer::Issuer;
47pub use crate::primitives::registrar::Registrar;
48pub use crate::primitives::scope::Scope;
49
50use crate::code_grant::resource::{Error as ResourceError};
51use crate::code_grant::error::{AuthorizationError, AccessTokenError};
52
53use url::Url;
54
55// Re-export the extension traits under prefixed names.
56pub use crate::code_grant::authorization::Extension as AuthorizationExtension;
57pub use crate::code_grant::accesstoken::Extension as AccessTokenExtension;
58pub use crate::code_grant::client_credentials::Extension as ClientCredentialsExtension;
59
60pub use crate::primitives::registrar::PreGrant;
61pub use self::authorization::*;
62pub use self::accesstoken::*;
63pub use self::client_credentials::ClientCredentialsFlow;
64pub use self::error::OAuthError;
65pub use self::refresh::RefreshFlow;
66pub use self::resource::*;
67pub use self::query::*;
68
69/// Answer from OwnerAuthorizer to indicate the owners choice.
70pub enum OwnerConsent<Response: WebResponse> {
71    /// The owner did not authorize the client.
72    Denied,
73
74    /// The owner has not yet decided, i.e. the returned page is a form for the user.
75    InProgress(Response),
76
77    /// Authorization was granted by the specified user.
78    Authorized(String),
79
80    /// An error occurred while checking authorization.
81    Error(Response::Error),
82}
83
84/// Modifiable reason for creating a response to the client.
85///
86/// Not all responses indicate failure. A redirect will also occur in the a regular of providing an
87/// access token to the third party client. When an error is present (see several methods) it is
88/// mostly possible to customize it. This hook provides advanced endpoints with the opportunity to
89/// set additional parameters and informational messages before they are encoded.
90///
91/// See the provided methods for more information and examples.
92#[derive(Debug)]
93pub struct Template<'a> {
94    inner: InnerTemplate<'a>,
95}
96
97/// The general manner of the response.
98///
99/// These are parallels for HTTP status codes of the same name.
100#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
101pub enum ResponseStatus {
102    /// The response is issued because the requesting party was not authorized.
103    Unauthorized,
104
105    /// The response redirects in the code grant flow.
106    Redirect,
107
108    /// The request was malformed.
109    BadRequest,
110
111    /// This response is normal and expected.
112    Ok,
113}
114
115/// Encapsulated different types of responses reasons.
116///
117/// Each variant contains some form of context information about the response. This can be used either
118/// purely informational or in some cases provides additional customization points. The addition of
119/// fields to some variant context can occur in any major release until `1.0`. It is discouraged to
120/// exhaustively match the fields directly. Since some context could not permit cloning, the enum will
121/// not derive this until this has shown unlikely but strongly requested. Please open an issue if you
122/// think the pros or cons should be evaluated differently.
123#[derive(Debug)]
124#[non_exhaustive]
125enum InnerTemplate<'a> {
126    /// Authorization to access the resource has not been granted.
127    Unauthorized {
128        /// The underlying cause for denying access.
129        ///
130        /// The http authorization header is to be set according to this field.
131        #[allow(dead_code)]
132        error: Option<ResourceError>,
133
134        /// Information on an access token error.
135        ///
136        /// Endpoints may modify this description to add additional explanatory text or a reference
137        /// uri for clients seeking explanation.
138        access_token_error: Option<&'a mut AccessTokenError>,
139    },
140
141    /// Redirect the user-agent to another url.
142    ///
143    /// The endpoint has the opportunity to inspect and modify error information to some extent.
144    /// For example to log an error rate or to provide a pointer to a custom human readable
145    /// explanation page. The response will generally not contain a body.
146    Redirect {
147        /// Information on an authorization error.
148        ///
149        /// Endpoints may modify this description to add additional explanatory text or a reference
150        /// uri for clients or resource owners seeking explanation.
151        authorization_error: Option<&'a mut AuthorizationError>,
152    },
153
154    /// The request did not conform to specification or was otheriwse invalid.
155    ///
156    /// As such, it was not handled further. Some processes still warrant a response body to be
157    /// set in the case of an invalid request, containing additional information for the client.
158    /// For example, an authorized client sending a malformed but authenticated request for an
159    /// access token will receive additional hints on the cause of his mistake.
160    BadRequest {
161        /// Information on an invalid-access-token-request error.
162        ///
163        /// Endpoints may modify this description to add additional explanatory text or a reference
164        /// uri for clients seeking explanation.
165        access_token_error: Option<&'a mut AccessTokenError>,
166    },
167
168    /// An expected, normal response.
169    ///
170    /// The content of the response may require precise semantics to be standard compliant,
171    /// therefore it is constructed using the `WebResponse` trait methods. Try not to tamper with
172    /// the format too much, such as unsetting a body etc. after the flow has finished.
173    Ok,
174}
175
176/// A pending solicitation to a resource owner.
177///
178/// This encapsulates the information available to an [`OwnerSolicitor`] when querying consent
179/// information.
180///
181/// [`OwnerSolicitor`]: trait.OwnerSolicitor.html
182pub struct Solicitation<'flow> {
183    pub(crate) grant: Cow<'flow, PreGrant>,
184    pub(crate) state: Option<Cow<'flow, str>>,
185}
186
187impl<'flow> Solicitation<'flow> {
188    /// Clone the solicitation into an owned structure.
189    ///
190    /// This mainly helps with sending it across threads.
191    pub fn into_owned(self) -> Solicitation<'static> {
192        Solicitation {
193            grant: Cow::Owned(self.grant.into_owned()),
194            state: self.state.map(|state| Cow::Owned(state.into_owned())),
195        }
196    }
197
198    /// Return the pre-grant associated with the request.
199    ///
200    /// The information in the `PreGrant` is the authoritative information on the client and scopes
201    /// associated with the request. It has already been validated against those settings and
202    /// restrictions that were applied when registering the client.
203    pub fn pre_grant(&self) -> &PreGrant {
204        self.grant.as_ref()
205    }
206
207    /// The state provided by the client request.
208    ///
209    /// This will need to be provided to the response back to the client so it must be preserved
210    /// across a redirect or a consent screen presented by the user agent.
211    pub fn state(&self) -> Option<&str> {
212        match self.state {
213            None => None,
214            Some(ref state) => Some(&state),
215        }
216    }
217
218    /// Create a new solicitation request from a pre grant.
219    ///
220    /// You usually wouldn't need to call this manually as it is called by the endpoint's flow and
221    /// then handed with all available information to the solicitor.
222    pub fn new(grant: &'flow PreGrant) -> Self {
223        Solicitation {
224            grant: Cow::Borrowed(grant),
225            state: None,
226        }
227    }
228
229    /// Add a client state to the solicitation.
230    pub fn with_state(self, state: &'flow str) -> Self {
231        Solicitation {
232            state: Some(Cow::Borrowed(state)),
233            ..self
234        }
235    }
236}
237
238/// Checks consent with the owner of a resource, identified in a request.
239///
240/// See [`frontends::simple`] for an implementation that permits arbitrary functions.
241///
242/// [`frontends::simple`]: ../frontends/simple/endpoint/struct.FnSolicitor.html
243pub trait OwnerSolicitor<Request: WebRequest> {
244    /// Ensure that a user (resource owner) is currently authenticated (for example via a session
245    /// cookie) and determine if he has agreed to the presented grants.
246    fn check_consent(&mut self, _: &mut Request, _: Solicitation) -> OwnerConsent<Request::Response>;
247}
248
249/// Determine the scopes applying to a request of a resource.
250///
251/// It is possible to use a slice of [`Scope`]s as an implementation of this trait. You can inspect
252/// the request that was used to access the resource for which the scopes are to be determined but
253/// should generally avoid doing so. Sometimes the scope depends on external parameters and this is
254/// unavoidable, e.g. if the scope is created dynamically from the path of the resource.
255///
256/// ## Example
257///
258/// Here's a possible new implementation that allows you to update your scope list at runtime:
259///
260/// ```
261/// # use oxide_auth::endpoint::Scopes;
262/// # use oxide_auth::endpoint::WebRequest;
263/// use oxide_auth::primitives::scope::Scope;
264/// use std::sync::{Arc, RwLock};
265///
266/// struct MyScopes {
267///     update: RwLock<Arc<[Scope]>>,
268///     current: Arc<[Scope]>,
269/// };
270///
271/// impl<R: WebRequest> Scopes<R> for MyScopes {
272///     fn scopes(&mut self, _: &mut R) -> &[Scope] {
273///         let update = self.update.read().unwrap();
274///         if !Arc::ptr_eq(&update, &self.current) {
275///             self.current = update.clone();
276///         }
277///         &self.current
278///     }
279/// }
280/// ```
281///
282/// [`Scope`]: ../primitives/scope/struct.Scope.html
283pub trait Scopes<Request: WebRequest> {
284    /// A list of alternative scopes.
285    ///
286    /// One of the scopes needs to be fulfilled by the access token in the request to grant access.
287    /// A scope is fulfilled if the set of its part is a subset of the parts in the grant. If the
288    /// slice is empty, then no scope can be fulfilled and the request is always blocked.
289    fn scopes(&mut self, request: &mut Request) -> &[Scope];
290}
291
292/// Abstraction of web requests with several different abstractions and constructors needed by an
293/// endpoint. It is assumed to originate from an HTTP request, as defined in the scope of the rfc,
294/// but theoretically other requests are possible.
295pub trait WebRequest {
296    /// The error generated from access of malformed or invalid requests.
297    type Error;
298
299    /// The corresponding type of Responses returned from this module.
300    type Response: WebResponse<Error = Self::Error>;
301
302    /// Retrieve a parsed version of the url query.
303    ///
304    /// An Err return value indicates a malformed query or an otherwise malformed WebRequest. Note
305    /// that an empty query should result in `Ok(HashMap::new())` instead of an Err.
306    fn query(&mut self) -> Result<Cow<dyn QueryParameter + 'static>, Self::Error>;
307
308    /// Retrieve the parsed `application/x-form-urlencoded` body of the request.
309    ///
310    /// An Err value / indicates a malformed body or a different Content-Type.
311    fn urlbody(&mut self) -> Result<Cow<dyn QueryParameter + 'static>, Self::Error>;
312
313    /// Contents of the authorization header or none if none exists. An Err value indicates a
314    /// malformed header or request.
315    fn authheader(&mut self) -> Result<Option<Cow<str>>, Self::Error>;
316}
317
318/// Response representation into which the Request is transformed by the code_grant types.
319///
320/// At most one of the methods `body_text`, `body_json` will be called. Some flows will
321/// however not call any of those methods.
322pub trait WebResponse {
323    /// The error generated when trying to construct an unhandled or invalid response.
324    type Error;
325
326    /// Set the response status to 200.
327    fn ok(&mut self) -> Result<(), Self::Error>;
328
329    /// A response which will redirect the user-agent to which the response is issued.
330    fn redirect(&mut self, url: Url) -> Result<(), Self::Error>;
331
332    /// Set the response status to 400.
333    fn client_error(&mut self) -> Result<(), Self::Error>;
334
335    /// Set the response status to 401 and add a `WWW-Authenticate` header.
336    fn unauthorized(&mut self, header_value: &str) -> Result<(), Self::Error>;
337
338    /// A pure text response with no special media type set.
339    fn body_text(&mut self, text: &str) -> Result<(), Self::Error>;
340
341    /// Json repsonse data, with media type `aplication/json.
342    fn body_json(&mut self, data: &str) -> Result<(), Self::Error>;
343}
344
345/// Intermediate trait to flow specific extensions.
346///
347/// The existence of this 1) promotes writing of extensions so that they can be reused independent
348/// of endpoint and request types; 2) makes it possible to provide some of these in this library.
349///
350/// Note that all methods will by default return `None` so that adding to other flows is possible
351/// without affecting existing implementations.
352pub trait Extension {
353    /// The handler for authorization code extensions.
354    fn authorization(&mut self) -> Option<&mut dyn AuthorizationExtension> {
355        None
356    }
357
358    /// The handler for access token extensions.
359    fn access_token(&mut self) -> Option<&mut dyn AccessTokenExtension> {
360        None
361    }
362
363    /// The handler for client credentials extensions.
364    fn client_credentials(&mut self) -> Option<&mut dyn ClientCredentialsExtension> {
365        None
366    }
367}
368
369/// Fuses requests and primitives into a coherent system to give a response.
370///
371/// There are multiple different valid ways to produce responses and react to internal errors for a
372/// single request type. This trait should provide those mechanisms, including trying to recover
373/// from primitive errors where appropriate.
374///
375/// To reduce the number of necessary impls and provide a single interface to a single trait, this
376/// trait defines accessor methods for all possibly needed primitives. Note that not all flows
377/// actually access all primitives. Thus, an implementation does not necessarily have to return
378/// something in `registrar`, `authorizer`, `issuer_mut` but failing to do so will also fail flows
379/// that try to use them.
380///
381/// # Panics
382///
383/// It is expected that the endpoint primitive functions are consistent, i.e. they don't begin
384/// returning `None` after having returned `Some(registrar)` previously for example. This ensures
385/// that the checks executed by the flow preparation methods catch missing primitives. When this
386/// contract is violated, the execution of a flow may lead to a panic.
387pub trait Endpoint<Request: WebRequest> {
388    /// The error typed used as the error representation of each flow.
389    type Error;
390
391    /// A registrar if this endpoint can access one.
392    ///
393    /// Returning `None` will implicate failing any flow that requires a registrar but does not
394    /// have any effect on flows that do not require one.
395    fn registrar(&self) -> Option<&dyn Registrar>;
396
397    /// An authorizer if this endpoint can access one.
398    ///
399    /// Returning `None` will implicate failing any flow that requires an authorizer but does not
400    /// have any effect on flows that do not require one.
401    fn authorizer_mut(&mut self) -> Option<&mut dyn Authorizer>;
402
403    /// An issuer if this endpoint can access one.
404    ///
405    /// Returning `None` will implicate failing any flow that requires an issuer but does not have
406    /// any effect on flows that do not require one.
407    fn issuer_mut(&mut self) -> Option<&mut dyn Issuer>;
408
409    /// Return the system that checks owner consent.
410    ///
411    /// Returning `None` will implicated failing the authorization code flow but does have any
412    /// effect on other flows.
413    fn owner_solicitor(&mut self) -> Option<&mut dyn OwnerSolicitor<Request>>;
414
415    /// Determine the required scopes for a request.
416    ///
417    /// The client must fulfill any one scope, so returning an empty slice will always deny the
418    /// request.
419    fn scopes(&mut self) -> Option<&mut dyn Scopes<Request>>;
420
421    /// Generate a prototype response.
422    ///
423    /// The endpoint can rely on this being called at most once for each flow, if it wants
424    /// to preallocate the response or return a handle on an existing prototype.
425    fn response(
426        &mut self, request: &mut Request, kind: Template,
427    ) -> Result<Request::Response, Self::Error>;
428
429    /// Wrap an error.
430    fn error(&mut self, err: OAuthError) -> Self::Error;
431
432    /// Wrap an error in the request/response types.
433    fn web_error(&mut self, err: Request::Error) -> Self::Error;
434
435    /// Get the central extension instance this endpoint.
436    ///
437    /// Returning `None` is the default implementation and acts as simply providing any extensions.
438    fn extension(&mut self) -> Option<&mut dyn Extension> {
439        None
440    }
441}
442
443impl<'a> Template<'a> {
444    /// Create an OK template
445    pub fn new_ok() -> Self {
446        InnerTemplate::Ok.into()
447    }
448
449    /// Create a bad request template
450    pub fn new_bad(access_token_error: Option<&'a mut AccessTokenError>) -> Self {
451        InnerTemplate::BadRequest { access_token_error }.into()
452    }
453
454    /// Create an unauthorized template
455    pub fn new_unauthorized(
456        error: Option<ResourceError>, access_token_error: Option<&'a mut AccessTokenError>,
457    ) -> Self {
458        InnerTemplate::Unauthorized {
459            error,
460            access_token_error,
461        }
462        .into()
463    }
464
465    /// Create a redirect template
466    pub fn new_redirect(authorization_error: Option<&'a mut AuthorizationError>) -> Self {
467        InnerTemplate::Redirect { authorization_error }.into()
468    }
469
470    /// The corresponding status code.
471    pub fn status(&self) -> ResponseStatus {
472        match self.inner {
473            InnerTemplate::Unauthorized { .. } => ResponseStatus::Unauthorized,
474            InnerTemplate::Redirect { .. } => ResponseStatus::Redirect,
475            InnerTemplate::BadRequest { .. } => ResponseStatus::BadRequest,
476            InnerTemplate::Ok => ResponseStatus::Ok,
477        }
478    }
479
480    /// Supplementary information about an error in the authorization code flow.
481    ///
482    /// The referenced object can be inspected and manipulated to provided additional information
483    /// that is specific to this server or endpoint. Such information could be an error page with
484    /// explanatory information or a customized message.
485    ///
486    /// ```
487    /// # use oxide_auth::endpoint::Template;
488    /// fn explain(mut template: Template) {
489    ///     if let Some(error) = template.authorization_error() {
490    ///         eprintln!("[authorization] An error occurred: {:?}", error.kind());
491    ///         error.explain("This server is still in its infancy. Sorry.");
492    ///         error.explain_uri("/authorization_error.html".parse().unwrap());
493    ///     }
494    /// }
495    /// ```
496    pub fn authorization_error(&mut self) -> Option<&mut AuthorizationError> {
497        match &mut self.inner {
498            InnerTemplate::Redirect {
499                authorization_error, ..
500            } => reborrow(authorization_error),
501            _ => None,
502        }
503    }
504
505    /// Supplementary information about an error in the access token flow.
506    ///
507    /// The referenced object can be inspected and manipulated to provided additional information
508    /// that is specific to this server or endpoint. Such information could be an error page with
509    /// explanatory information or a customized message.
510    ///
511    /// ```
512    /// # use oxide_auth::endpoint::Template;
513    /// fn explain(mut template: Template) {
514    ///     if let Some(error) = template.access_token_error() {
515    ///         eprintln!("[access_code] An error occurred: {:?}", error.kind());
516    ///         error.explain("This server is still in its infancy. Sorry.");
517    ///         error.explain_uri("/access_token_error.html".parse().unwrap());
518    ///     }
519    /// }
520    /// ```
521    pub fn access_token_error(&mut self) -> Option<&mut AccessTokenError> {
522        match &mut self.inner {
523            InnerTemplate::Unauthorized {
524                access_token_error, ..
525            } => reborrow(access_token_error),
526            InnerTemplate::BadRequest {
527                access_token_error, ..
528            } => reborrow(access_token_error),
529            _ => None,
530        }
531    }
532}
533
534/// Reborrow contained optional reference.
535///
536/// Slightly tweaked from an `Into`, there is `Option<&'a mut T>` from `&'a mut Option<T>`.
537fn reborrow<'a, T>(opt: &'a mut Option<&mut T>) -> Option<&'a mut T> {
538    match opt {
539        // Magically does correct lifetime coercision.
540        Some(inner) => Some(inner),
541        None => None,
542    }
543}
544
545impl<'a, W: WebRequest> WebRequest for &'a mut W {
546    type Error = W::Error;
547    type Response = W::Response;
548
549    fn query(&mut self) -> Result<Cow<dyn QueryParameter + 'static>, Self::Error> {
550        (**self).query()
551    }
552
553    fn urlbody(&mut self) -> Result<Cow<dyn QueryParameter + 'static>, Self::Error> {
554        (**self).urlbody()
555    }
556
557    fn authheader(&mut self) -> Result<Option<Cow<str>>, Self::Error> {
558        (**self).authheader()
559    }
560}
561
562impl<'a, R: WebRequest, E: Endpoint<R>> Endpoint<R> for &'a mut E {
563    type Error = E::Error;
564
565    fn registrar(&self) -> Option<&dyn Registrar> {
566        (**self).registrar()
567    }
568
569    fn authorizer_mut(&mut self) -> Option<&mut dyn Authorizer> {
570        (**self).authorizer_mut()
571    }
572
573    fn issuer_mut(&mut self) -> Option<&mut dyn Issuer> {
574        (**self).issuer_mut()
575    }
576
577    fn owner_solicitor(&mut self) -> Option<&mut dyn OwnerSolicitor<R>> {
578        (**self).owner_solicitor()
579    }
580
581    fn scopes(&mut self) -> Option<&mut dyn Scopes<R>> {
582        (**self).scopes()
583    }
584
585    fn response(&mut self, request: &mut R, kind: Template) -> Result<R::Response, Self::Error> {
586        (**self).response(request, kind)
587    }
588
589    fn error(&mut self, err: OAuthError) -> Self::Error {
590        (**self).error(err)
591    }
592
593    fn web_error(&mut self, err: R::Error) -> Self::Error {
594        (**self).web_error(err)
595    }
596
597    fn extension(&mut self) -> Option<&mut dyn Extension> {
598        (**self).extension()
599    }
600}
601
602impl<'a, R: WebRequest, E: Endpoint<R> + 'a> Endpoint<R> for Box<E> {
603    type Error = E::Error;
604
605    fn registrar(&self) -> Option<&dyn Registrar> {
606        (**self).registrar()
607    }
608
609    fn authorizer_mut(&mut self) -> Option<&mut dyn Authorizer> {
610        (**self).authorizer_mut()
611    }
612
613    fn issuer_mut(&mut self) -> Option<&mut dyn Issuer> {
614        (**self).issuer_mut()
615    }
616
617    fn owner_solicitor(&mut self) -> Option<&mut dyn OwnerSolicitor<R>> {
618        (**self).owner_solicitor()
619    }
620
621    fn scopes(&mut self) -> Option<&mut dyn Scopes<R>> {
622        (**self).scopes()
623    }
624
625    fn response(&mut self, request: &mut R, kind: Template) -> Result<R::Response, Self::Error> {
626        (**self).response(request, kind)
627    }
628
629    fn error(&mut self, err: OAuthError) -> Self::Error {
630        (**self).error(err)
631    }
632
633    fn web_error(&mut self, err: R::Error) -> Self::Error {
634        (**self).web_error(err)
635    }
636
637    fn extension(&mut self) -> Option<&mut dyn Extension> {
638        (**self).extension()
639    }
640}
641
642impl Extension for () {}
643
644impl<'a, W: WebRequest, S: OwnerSolicitor<W> + 'a + ?Sized> OwnerSolicitor<W> for &'a mut S {
645    fn check_consent(
646        &mut self, request: &mut W, solicitation: Solicitation,
647    ) -> OwnerConsent<W::Response> {
648        (**self).check_consent(request, solicitation)
649    }
650}
651
652impl<'a, W: WebRequest, S: OwnerSolicitor<W> + 'a + ?Sized> OwnerSolicitor<W> for Box<S> {
653    fn check_consent(
654        &mut self, request: &mut W, solicitation: Solicitation,
655    ) -> OwnerConsent<W::Response> {
656        (**self).check_consent(request, solicitation)
657    }
658}
659
660impl<W: WebRequest> Scopes<W> for [Scope] {
661    fn scopes(&mut self, _: &mut W) -> &[Scope] {
662        self
663    }
664}
665
666impl<W: WebRequest> Scopes<W> for Vec<Scope> {
667    fn scopes(&mut self, _: &mut W) -> &[Scope] {
668        self.as_slice()
669    }
670}
671
672impl<'a, W: WebRequest> Scopes<W> for &'a [Scope] {
673    fn scopes(&mut self, _: &mut W) -> &[Scope] {
674        self
675    }
676}
677
678impl<'a, W: WebRequest, S: Scopes<W> + 'a + ?Sized> Scopes<W> for &'a mut S {
679    fn scopes(&mut self, request: &mut W) -> &[Scope] {
680        (**self).scopes(request)
681    }
682}
683
684impl<'a, W: WebRequest, S: Scopes<W> + 'a + ?Sized> Scopes<W> for Box<S> {
685    fn scopes(&mut self, request: &mut W) -> &[Scope] {
686        (**self).scopes(request)
687    }
688}
689
690impl<'a> From<InnerTemplate<'a>> for Template<'a> {
691    fn from(inner: InnerTemplate<'a>) -> Self {
692        Template { inner }
693    }
694}
695
696/// Check if the header is an authorization method
697pub fn is_authorization_method<'h>(header: &'h str, method: &'static str) -> Option<&'h str> {
698    let header_method = header.get(..method.len())?;
699    if header_method.eq_ignore_ascii_case(method) {
700        Some(&header[method.len()..])
701    } else {
702        None
703    }
704}