oxide_auth_async/endpoint/
authorization.rs1use std::{borrow::Cow, marker::PhantomData};
2
3use oxide_auth::{
4 endpoint::{WebResponse, QueryParameter, NormalizedParameter},
5 code_grant::authorization::{Error as AuthorizationError, Request as AuthorizationRequest},
6};
7
8use crate::code_grant::authorization::{
9 authorization_code, Endpoint as AuthorizationEndpoint, Extension, Pending,
10};
11
12use super::*;
13use url::Url;
14
15pub struct AuthorizationFlow<E, R>
17where
18 E: Endpoint<R>,
19 R: WebRequest,
20{
21 endpoint: WrappedAuthorization<E, R>,
22}
23
24struct WrappedAuthorization<E: Endpoint<R>, R>
25where
26 E: Endpoint<R>,
27 R: WebRequest,
28{
29 inner: E,
30 extension_fallback: (),
31 r_type: PhantomData<R>,
32}
33
34#[derive(Clone)]
35pub struct WrappedRequest<R>
36where
37 R: WebRequest,
38{
39 query: NormalizedParameter,
41
42 error: Option<R::Error>,
44}
45
46struct AuthorizationPending<'a, E: 'a, R: 'a>
47where
48 E: Endpoint<R> + Send,
49 R: WebRequest,
50{
51 endpoint: &'a mut WrappedAuthorization<E, R>,
52 pending: Pending,
53 request: R,
54}
55
56struct AuthorizationPartial<'a, E: 'a, R: 'a>
61where
62 E: Endpoint<R> + Send,
63 R: WebRequest,
64{
65 inner: AuthorizationPartialInner<'a, E, R>,
66
67 _with_request: Option<Box<dyn FnOnce(R) + Send>>,
69}
70
71enum AuthorizationPartialInner<'a, E: 'a, R: 'a>
73where
74 E: Endpoint<R> + Send,
75 R: WebRequest,
76{
77 Pending {
79 pending: AuthorizationPending<'a, E, R>,
81 },
82
83 Failed {
85 request: R,
87
88 response: R::Response,
93 },
94
95 Error {
97 request: R,
99
100 error: E::Error,
102 },
103}
104
105impl<E, R> AuthorizationFlow<E, R>
106where
107 E: Endpoint<R> + Send + Sync,
108 R: WebRequest + Send + Sync,
109 <R as WebRequest>::Error: Send + Sync,
110{
111 pub fn prepare(mut endpoint: E) -> Result<Self, E::Error> {
122 if endpoint.registrar().is_none() {
123 return Err(endpoint.error(OAuthError::PrimitiveError));
124 }
125
126 if endpoint.authorizer_mut().is_none() {
127 return Err(endpoint.error(OAuthError::PrimitiveError));
128 }
129
130 Ok(AuthorizationFlow {
131 endpoint: WrappedAuthorization {
132 inner: endpoint,
133 extension_fallback: (),
134 r_type: PhantomData,
135 },
136 })
137 }
138
139 pub async fn execute(&mut self, mut request: R) -> Result<R::Response, E::Error> {
149 let negotiated =
150 authorization_code(&mut self.endpoint, &WrappedRequest::new(&mut request)).await;
151
152 let inner = match negotiated {
153 Err(err) => match authorization_error(&mut self.endpoint.inner, &mut request, err) {
154 Ok(response) => AuthorizationPartialInner::Failed { request, response },
155 Err(error) => AuthorizationPartialInner::Error { request, error },
156 },
157 Ok(negotiated) => AuthorizationPartialInner::Pending {
158 pending: AuthorizationPending {
159 endpoint: &mut self.endpoint,
160 pending: negotiated,
161 request,
162 },
163 },
164 };
165
166 let partial = AuthorizationPartial {
167 inner,
168 _with_request: None,
169 };
170
171 partial.finish().await
172 }
173}
174
175impl<'a, E, R> AuthorizationPartial<'a, E, R>
176where
177 E: Endpoint<R> + Send,
178 R: WebRequest + Send,
179{
180 pub async fn finish(self) -> Result<R::Response, E::Error> {
185 let (_request, result) = match self.inner {
186 AuthorizationPartialInner::Pending { pending } => pending.finish().await,
187 AuthorizationPartialInner::Failed { request, response } => (request, Ok(response)),
188 AuthorizationPartialInner::Error { request, error } => (request, Err(error)),
189 };
190
191 result
192 }
193}
194
195fn authorization_error<E, R>(
196 endpoint: &mut E, request: &mut R, error: AuthorizationError,
197) -> Result<R::Response, E::Error>
198where
199 E: Endpoint<R>,
200 R: WebRequest,
201{
202 match error {
203 AuthorizationError::Ignore => Err(endpoint.error(OAuthError::DenySilently)),
204 AuthorizationError::Redirect(mut target) => {
205 let mut response =
206 endpoint.response(request, Template::new_redirect(Some(target.description())))?;
207 response
208 .redirect(target.into())
209 .map_err(|err| endpoint.web_error(err))?;
210 Ok(response)
211 }
212 AuthorizationError::PrimitiveError => Err(endpoint.error(OAuthError::PrimitiveError)),
213 }
214}
215
216impl<'a, E, R> AuthorizationPending<'a, E, R>
217where
218 E: Endpoint<R> + Send,
219 R: WebRequest + Send,
220{
221 async fn finish(mut self) -> (R, Result<R::Response, E::Error>) {
223 let checked = self
224 .endpoint
225 .owner_solicitor()
226 .check_consent(&mut self.request, self.pending.as_solicitation())
227 .await;
228
229 match checked {
230 OwnerConsent::Denied => self.deny(),
231 OwnerConsent::InProgress(resp) => self.in_progress(resp),
232 OwnerConsent::Authorized(who) => self.authorize(who).await,
233 OwnerConsent::Error(err) => (self.request, Err(self.endpoint.inner.web_error(err))),
234 }
235 }
236
237 fn in_progress(self, response: R::Response) -> (R, Result<R::Response, E::Error>) {
244 (self.request, Ok(response))
245 }
246
247 fn deny(mut self) -> (R, Result<R::Response, E::Error>) {
249 let result = self.pending.deny();
250 let result = Self::convert_result(result, &mut self.endpoint.inner, &mut self.request);
251
252 (self.request, result)
253 }
254
255 async fn authorize(mut self, who: String) -> (R, Result<R::Response, E::Error>) {
257 let result = self.pending.authorize(self.endpoint, who.into()).await;
258 let result = Self::convert_result(result, &mut self.endpoint.inner, &mut self.request);
259
260 (self.request, result)
261 }
262
263 fn convert_result(
264 result: Result<Url, AuthorizationError>, endpoint: &mut E, request: &mut R,
265 ) -> Result<R::Response, E::Error> {
266 match result {
267 Ok(url) => {
268 let mut response = endpoint.response(request, Template::new_redirect(None))?;
269 response.redirect(url).map_err(|err| endpoint.web_error(err))?;
270 Ok(response)
271 }
272 Err(err) => authorization_error(endpoint, request, err),
273 }
274 }
275}
276
277impl<E, R> WrappedAuthorization<E, R>
278where
279 E: Endpoint<R>,
280 R: WebRequest,
281{
282 fn owner_solicitor(&mut self) -> &mut (dyn OwnerSolicitor<R> + Send) {
283 self.inner.owner_solicitor().unwrap()
284 }
285}
286
287impl<E, R> AuthorizationEndpoint for WrappedAuthorization<E, R>
288where
289 E: Endpoint<R>,
290 R: WebRequest,
291{
292 fn registrar(&self) -> &(dyn Registrar + Sync) {
293 self.inner.registrar().unwrap()
294 }
295
296 fn authorizer(&mut self) -> &mut (dyn Authorizer + Send) {
297 self.inner.authorizer_mut().unwrap()
298 }
299
300 fn extension(&mut self) -> &mut (dyn Extension + Send) {
301 self.inner
302 .extension()
303 .and_then(super::Extension::authorization)
304 .unwrap_or(&mut self.extension_fallback)
305 }
306}
307
308impl<'a, R> WrappedRequest<R>
309where
310 R: WebRequest + 'a,
311{
312 pub fn new(request: &'a mut R) -> Self {
313 Self::new_or_fail(request).unwrap_or_else(Self::from_err)
314 }
315
316 fn new_or_fail(request: &'a mut R) -> Result<Self, R::Error> {
317 Ok(WrappedRequest {
318 query: request.query()?.into_owned(),
319 error: None,
320 })
321 }
322
323 fn from_err(err: R::Error) -> Self {
324 WrappedRequest {
325 query: Default::default(),
326 error: Some(err),
327 }
328 }
329}
330
331impl<R> AuthorizationRequest for WrappedRequest<R>
332where
333 R: WebRequest,
334{
335 fn valid(&self) -> bool {
336 self.error.is_none()
337 }
338
339 fn client_id(&self) -> Option<Cow<str>> {
340 self.query.unique_value("client_id")
341 }
342
343 fn scope(&self) -> Option<Cow<str>> {
344 self.query.unique_value("scope")
345 }
346
347 fn redirect_uri(&self) -> Option<Cow<str>> {
348 self.query.unique_value("redirect_uri")
349 }
350
351 fn state(&self) -> Option<Cow<str>> {
352 self.query.unique_value("state")
353 }
354
355 fn response_type(&self) -> Option<Cow<str>> {
356 self.query.unique_value("response_type")
357 }
358
359 fn extension(&self, key: &str) -> Option<Cow<str>> {
360 self.query.unique_value(key)
361 }
362}