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