oxide_auth_async/endpoint/
resource.rs1use std::{marker::PhantomData, borrow::Cow};
2
3use oxide_auth::code_grant::resource::{Error as ResourceError, Request as ResourceRequest};
4use oxide_auth::{
5 endpoint::{Scope, WebResponse},
6 primitives::grant::Grant,
7};
8
9use crate::code_grant::resource::{protect, Endpoint as ResourceEndpoint};
10
11use super::*;
12
13pub struct ResourceFlow<E, R>
15where
16 E: Endpoint<R>,
17 R: WebRequest,
18{
19 endpoint: WrappedResource<E, R>,
20}
21
22struct WrappedResource<E, R>(E, PhantomData<R>)
23where
24 E: Endpoint<R>,
25 R: WebRequest;
26
27struct WrappedRequest<R: WebRequest> {
28 request: PhantomData<R>,
30
31 authorization: Option<String>,
33
34 error: Option<R::Error>,
38}
39
40struct Scoped<'a, E: 'a, R: 'a> {
41 request: &'a mut R,
42 endpoint: &'a mut E,
43}
44
45impl<E, R> ResourceFlow<E, R>
46where
47 E: Endpoint<R> + Send + Sync,
48 R: WebRequest + Send + Sync,
49 <R as WebRequest>::Error: Send + Sync,
50{
51 pub fn prepare(mut endpoint: E) -> Result<Self, E::Error> {
62 if endpoint.issuer_mut().is_none() {
63 return Err(endpoint.error(OAuthError::PrimitiveError));
64 }
65
66 if endpoint.scopes().is_none() {
67 return Err(endpoint.error(OAuthError::PrimitiveError));
68 }
69
70 Ok(ResourceFlow {
71 endpoint: WrappedResource(endpoint, PhantomData),
72 })
73 }
74
75 pub async fn execute(&mut self, mut request: R) -> Result<Grant, Result<R::Response, E::Error>> {
82 let protected = {
83 let wrapped = WrappedRequest::new(&mut request);
84
85 let mut scoped = Scoped {
86 request: &mut request,
87 endpoint: &mut self.endpoint.0,
88 };
89
90 protect(&mut scoped, &wrapped).await
91 };
92
93 protected.map_err(|err| self.denied(&mut request, err))
94 }
95
96 fn denied(&mut self, request: &mut R, error: ResourceError) -> Result<R::Response, E::Error> {
97 let template = match &error {
98 ResourceError::AccessDenied { .. } => Template::new_unauthorized(None, None),
99 ResourceError::NoAuthentication { .. } => Template::new_unauthorized(None, None),
100 ResourceError::InvalidRequest { .. } => Template::new_bad(None),
101 ResourceError::PrimitiveError => {
102 return Err(self.endpoint.0.error(OAuthError::PrimitiveError))
103 }
104 };
105
106 let mut response = self.endpoint.0.response(request, template)?;
107 response
108 .unauthorized(&error.www_authenticate())
109 .map_err(|err| self.endpoint.0.web_error(err))?;
110
111 Ok(response)
112 }
113}
114
115impl<R: WebRequest> WrappedRequest<R> {
116 fn new(request: &mut R) -> Self {
117 let token = match request.authheader() {
118 Ok(Some(token)) => Some(token.into_owned()),
120 Ok(None) => None,
121 Err(error) => return Self::from_error(error),
122 };
123
124 WrappedRequest {
125 request: PhantomData,
126 authorization: token,
127 error: None,
128 }
129 }
130
131 fn from_error(error: R::Error) -> Self {
132 WrappedRequest {
133 request: PhantomData,
134 authorization: None,
135 error: Some(error),
136 }
137 }
138}
139
140impl<'a, E: 'a, R: 'a> ResourceEndpoint for Scoped<'a, E, R>
141where
142 E: Endpoint<R>,
143 R: WebRequest,
144{
145 fn scopes(&mut self) -> &[Scope] {
146 self.endpoint.scopes().unwrap().scopes(self.request)
147 }
148
149 fn issuer(&mut self) -> &mut (dyn Issuer + Send) {
150 self.endpoint.issuer_mut().unwrap()
151 }
152}
153
154impl<R: WebRequest> ResourceRequest for WrappedRequest<R> {
155 fn valid(&self) -> bool {
156 self.error.is_none()
157 }
158
159 fn token(&self) -> Option<Cow<str>> {
160 self.authorization.as_deref().map(Cow::Borrowed)
161 }
162}