1#![warn(missing_docs)]
6
7use actix::{MailboxError, Message};
8use actix_web::{
9 body::BoxBody,
10 dev::Payload,
11 http::{
12 header::{self, HeaderMap, InvalidHeaderValue},
13 StatusCode,
14 },
15 web::Form,
16 web::Query,
17 FromRequest, HttpRequest, HttpResponse, HttpResponseBuilder, Responder, ResponseError,
18};
19use futures::future::{self, FutureExt, LocalBoxFuture, Ready};
20use oxide_auth::{
21 endpoint::{Endpoint, NormalizedParameter, OAuthError, QueryParameter, WebRequest, WebResponse},
22 frontends::simple::endpoint::Error,
23};
24use std::{borrow::Cow, convert::TryFrom, error, fmt};
25use url::Url;
26
27mod operations;
28
29pub use operations::{Authorize, Refresh, Resource, Token, ClientCredentials};
30
31pub trait OAuthOperation: Sized + 'static {
89 type Item: 'static;
91
92 type Error: fmt::Debug + 'static;
94
95 fn run<E>(self, endpoint: E) -> Result<Self::Item, Self::Error>
97 where
98 E: Endpoint<OAuthRequest>,
99 WebError: From<E::Error>;
100
101 fn wrap<Extras>(self, extras: Extras) -> OAuthMessage<Self, Extras> {
103 OAuthMessage(self, extras)
104 }
105}
106
107pub struct OAuthMessage<Operation, Extras>(Operation, Extras);
109
110#[derive(Clone, Debug)]
111pub struct OAuthRequest {
116 auth: Option<String>,
117 query: Option<NormalizedParameter>,
118 body: Option<NormalizedParameter>,
119}
120
121impl OAuthResponse {
122 pub fn get_headers(&self) -> HeaderMap {
124 self.headers.clone()
125 }
126
127 pub fn get_body(&self) -> Option<String> {
129 self.body.clone()
130 }
131}
132
133pub struct OAuthResource {
138 auth: Option<String>,
139}
140
141#[derive(Clone, Debug)]
142pub struct OAuthResponse {
144 status: StatusCode,
145 headers: HeaderMap,
146 body: Option<String>,
147}
148
149#[derive(Debug)]
150pub enum WebError {
152 Endpoint(OAuthError),
154
155 Header(InvalidHeaderValue),
157
158 Encoding,
160
161 Form,
163
164 Query,
166
167 Body,
169
170 Authorization,
172
173 Canceled,
175
176 Mailbox,
178
179 InternalError(Option<String>),
181}
182
183impl OAuthRequest {
184 pub async fn new(req: HttpRequest, mut payload: Payload) -> Result<Self, WebError> {
186 let query = Query::extract(&req)
187 .await
188 .ok()
189 .map(|q: Query<NormalizedParameter>| q.into_inner());
190 let body = Form::from_request(&req, &mut payload)
191 .await
192 .ok()
193 .map(|b: Form<NormalizedParameter>| b.into_inner());
194
195 let mut all_auth = req.headers().get_all(header::AUTHORIZATION);
196 let optional = all_auth.next();
197
198 let auth = if all_auth.next().is_some() {
199 return Err(WebError::Authorization);
200 } else {
201 optional.and_then(|hv| hv.to_str().ok().map(str::to_owned))
202 };
203
204 Ok(OAuthRequest { auth, query, body })
205 }
206
207 pub fn authorization_header(&self) -> Option<&str> {
209 self.auth.as_deref()
210 }
211
212 pub fn query(&self) -> Option<&NormalizedParameter> {
214 self.query.as_ref()
215 }
216
217 pub fn query_mut(&mut self) -> Option<&mut NormalizedParameter> {
219 self.query.as_mut()
220 }
221
222 pub fn body(&self) -> Option<&NormalizedParameter> {
224 self.body.as_ref()
225 }
226}
227
228impl OAuthResource {
229 pub fn new(req: &HttpRequest) -> Result<Self, WebError> {
231 let mut all_auth = req.headers().get_all(header::AUTHORIZATION);
232 let optional = all_auth.next();
233
234 let auth = if all_auth.next().is_some() {
235 return Err(WebError::Authorization);
236 } else {
237 optional.and_then(|hv| hv.to_str().ok().map(str::to_owned))
238 };
239
240 Ok(OAuthResource { auth })
241 }
242
243 pub fn into_request(self) -> OAuthRequest {
245 OAuthRequest {
246 query: None,
247 body: None,
248 auth: self.auth,
249 }
250 }
251}
252
253impl OAuthResponse {
254 pub fn ok() -> Self {
256 OAuthResponse {
257 status: StatusCode::OK,
258 headers: HeaderMap::new(),
259 body: None,
260 }
261 }
262
263 pub fn content_type(mut self, content_type: &str) -> Result<Self, WebError> {
265 self.headers
266 .insert(header::CONTENT_TYPE, TryFrom::try_from(content_type)?);
267 Ok(self)
268 }
269
270 pub fn body(mut self, body: &str) -> Self {
272 self.body = Some(body.to_owned());
273 self
274 }
275}
276
277impl<Operation, Extras> OAuthMessage<Operation, Extras> {
278 pub fn into_inner(self) -> (Operation, Extras) {
280 (self.0, self.1)
281 }
282}
283
284impl WebRequest for OAuthRequest {
285 type Error = WebError;
286 type Response = OAuthResponse;
287
288 fn query(&mut self) -> Result<Cow<dyn QueryParameter + 'static>, Self::Error> {
289 self.query
290 .as_ref()
291 .map(|q| Cow::Borrowed(q as &dyn QueryParameter))
292 .ok_or(WebError::Query)
293 }
294
295 fn urlbody(&mut self) -> Result<Cow<dyn QueryParameter + 'static>, Self::Error> {
296 self.body
297 .as_ref()
298 .map(|b| Cow::Borrowed(b as &dyn QueryParameter))
299 .ok_or(WebError::Body)
300 }
301
302 fn authheader(&mut self) -> Result<Option<Cow<str>>, Self::Error> {
303 Ok(self.auth.as_deref().map(Cow::Borrowed))
304 }
305}
306
307impl WebResponse for OAuthResponse {
308 type Error = WebError;
309
310 fn ok(&mut self) -> Result<(), Self::Error> {
311 self.status = StatusCode::OK;
312 Ok(())
313 }
314
315 fn redirect(&mut self, url: Url) -> Result<(), Self::Error> {
316 self.status = StatusCode::FOUND;
317 let location = String::from(url);
318 self.headers
319 .insert(header::LOCATION, TryFrom::try_from(location)?);
320 Ok(())
321 }
322
323 fn client_error(&mut self) -> Result<(), Self::Error> {
324 self.status = StatusCode::BAD_REQUEST;
325 Ok(())
326 }
327
328 fn unauthorized(&mut self, kind: &str) -> Result<(), Self::Error> {
329 self.status = StatusCode::UNAUTHORIZED;
330 self.headers
331 .insert(header::WWW_AUTHENTICATE, TryFrom::try_from(kind)?);
332 Ok(())
333 }
334
335 fn body_text(&mut self, text: &str) -> Result<(), Self::Error> {
336 self.body = Some(text.to_owned());
337 self.headers
338 .insert(header::CONTENT_TYPE, TryFrom::try_from("text/plain")?);
339 Ok(())
340 }
341
342 fn body_json(&mut self, json: &str) -> Result<(), Self::Error> {
343 self.body = Some(json.to_owned());
344 self.headers
345 .insert(header::CONTENT_TYPE, TryFrom::try_from("application/json")?);
346 Ok(())
347 }
348}
349
350impl<Operation, Extras> Message for OAuthMessage<Operation, Extras>
351where
352 Operation: OAuthOperation + 'static,
353{
354 type Result = Result<Operation::Item, Operation::Error>;
355}
356
357impl FromRequest for OAuthRequest {
358 type Error = WebError;
359 type Future = LocalBoxFuture<'static, Result<Self, Self::Error>>;
360
361 fn from_request(req: &HttpRequest, payload: &mut Payload) -> Self::Future {
362 Self::new(req.clone(), payload.take()).boxed_local()
363 }
364}
365
366impl FromRequest for OAuthResource {
367 type Error = WebError;
368 type Future = Ready<Result<Self, Self::Error>>;
369
370 fn from_request(req: &HttpRequest, _: &mut Payload) -> Self::Future {
371 future::ready(Self::new(req))
372 }
373}
374
375impl Responder for OAuthResponse {
376 type Body = BoxBody;
377
378 fn respond_to(self, _: &HttpRequest) -> HttpResponse {
379 let mut builder = HttpResponseBuilder::new(self.status);
380 for (k, v) in self.headers.into_iter() {
381 builder.insert_header((k, v.to_owned()));
382 }
383
384 if let Some(body) = self.body {
385 builder.body(body)
386 } else {
387 builder.finish()
388 }
389 }
390}
391
392impl From<OAuthResource> for OAuthRequest {
393 fn from(o: OAuthResource) -> Self {
394 o.into_request()
395 }
396}
397
398impl Default for OAuthResponse {
399 fn default() -> Self {
400 OAuthResponse {
401 status: StatusCode::OK,
402 headers: HeaderMap::new(),
403 body: None,
404 }
405 }
406}
407
408impl From<Error<OAuthRequest>> for WebError {
409 fn from(e: Error<OAuthRequest>) -> Self {
410 match e {
411 Error::Web(e) => e,
412 Error::OAuth(e) => e.into(),
413 }
414 }
415}
416
417impl From<InvalidHeaderValue> for WebError {
418 fn from(e: InvalidHeaderValue) -> Self {
419 WebError::Header(e)
420 }
421}
422
423impl From<MailboxError> for WebError {
424 fn from(e: MailboxError) -> Self {
425 match e {
426 MailboxError::Closed => WebError::Mailbox,
427 MailboxError::Timeout => WebError::Canceled,
428 }
429 }
430}
431
432impl From<OAuthError> for WebError {
433 fn from(e: OAuthError) -> Self {
434 WebError::Endpoint(e)
435 }
436}
437
438impl fmt::Display for WebError {
439 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
440 match *self {
441 WebError::Endpoint(ref e) => write!(f, "Endpoint, {}", e),
442 WebError::Header(ref e) => write!(f, "Couldn't set header, {}", e),
443 WebError::Encoding => write!(f, "Error decoding request"),
444 WebError::Form => write!(f, "Request is not a form"),
445 WebError::Query => write!(f, "No query present"),
446 WebError::Body => write!(f, "No body present"),
447 WebError::Authorization => write!(f, "Request has invalid Authorization headers"),
448 WebError::Canceled => write!(f, "Operation canceled"),
449 WebError::Mailbox => write!(f, "An actor's mailbox was full"),
450 WebError::InternalError(None) => write!(f, "An internal server error occured"),
451 WebError::InternalError(Some(ref e)) => write!(f, "An internal server error occured: {}", e),
452 }
453 }
454}
455
456impl error::Error for WebError {
457 fn source(&self) -> Option<&(dyn error::Error + 'static)> {
458 match *self {
459 WebError::Endpoint(ref e) => e.source(),
460 WebError::Header(ref e) => e.source(),
461 WebError::Encoding
462 | WebError::Form
463 | WebError::Authorization
464 | WebError::Query
465 | WebError::Body
466 | WebError::Canceled
467 | WebError::Mailbox
468 | WebError::InternalError(_) => None,
469 }
470 }
471}
472
473impl ResponseError for WebError {
474 }