1use std::borrow::Cow;
2use std::str::from_utf8;
3use std::marker::PhantomData;
4
5use base64::Engine;
6use base64::engine::general_purpose::STANDARD;
7
8use crate::code_grant::client_credentials::{
9 client_credentials, Error as ClientCredentialsError, Extension,
10 Endpoint as ClientCredentialsEndpoint, Request as ClientCredentialsRequest,
11};
12use crate::code_grant::error::{AccessTokenError, AccessTokenErrorType};
13use crate::code_grant::refresh::ErrorDescription;
14use crate::primitives::{registrar::Registrar, issuer::Issuer};
15use super::{
16 Endpoint, InnerTemplate, OAuthError, QueryParameter, WebRequest, WebResponse,
17 is_authorization_method, OwnerConsent,
18};
19
20pub struct ClientCredentialsFlow<E, R>
30where
31 E: Endpoint<R>,
32 R: WebRequest,
33{
34 endpoint: WrappedToken<E, R>,
35 allow_credentials_in_body: bool,
36 allow_refresh_token: bool,
37}
38
39struct WrappedToken<E: Endpoint<R>, R: WebRequest> {
40 inner: E,
41 extension_fallback: (),
42 r_type: PhantomData<R>,
43}
44
45struct WrappedRequest<'a, R: WebRequest + 'a> {
46 request: PhantomData<R>,
48
49 body: Cow<'a, dyn QueryParameter + 'static>,
51
52 authorization: Option<Authorization>,
54
55 error: Option<FailParse<R::Error>>,
57
58 allow_credentials_in_body: bool,
60}
61
62struct Invalid;
63
64enum FailParse<E> {
65 Invalid,
66 Err(E),
67}
68
69struct Authorization(String, Vec<u8>);
70
71impl<E, R> ClientCredentialsFlow<E, R>
72where
73 E: Endpoint<R>,
74 R: WebRequest,
75{
76 pub fn prepare(mut endpoint: E) -> Result<Self, E::Error> {
87 if endpoint.registrar().is_none() {
88 return Err(endpoint.error(OAuthError::PrimitiveError));
89 }
90
91 if endpoint.issuer_mut().is_none() {
92 return Err(endpoint.error(OAuthError::PrimitiveError));
93 }
94
95 Ok(ClientCredentialsFlow {
96 endpoint: WrappedToken {
97 inner: endpoint,
98 extension_fallback: (),
99 r_type: PhantomData,
100 },
101 allow_credentials_in_body: false,
102 allow_refresh_token: false,
103 })
104 }
105
106 pub fn allow_credentials_in_body(&mut self, allow: bool) {
114 self.allow_credentials_in_body = allow;
115 }
116
117 pub fn allow_refresh_token(&mut self, allow: bool) {
128 self.allow_refresh_token = allow;
129 }
130
131 pub fn execute(&mut self, mut request: R) -> Result<R::Response, E::Error> {
138 let pending = client_credentials(
139 &mut self.endpoint,
140 &WrappedRequest::new(&mut request, self.allow_credentials_in_body),
141 );
142 let pending = match pending {
143 Err(error) => {
144 return client_credentials_error(&mut self.endpoint.inner, &mut request, error)
145 }
146 Ok(pending) => pending,
147 };
148
149 let consent = self
150 .endpoint
151 .inner
152 .owner_solicitor()
153 .unwrap()
154 .check_consent(&mut request, pending.as_solicitation());
155
156 let owner_id = match consent {
157 OwnerConsent::Authorized(owner_id) => owner_id,
158 OwnerConsent::Error(error) => return Err(self.endpoint.inner.web_error(error)),
159 OwnerConsent::InProgress(..) => {
160 return Err(self.endpoint.inner.error(OAuthError::PrimitiveError));
163 }
164 OwnerConsent::Denied => {
165 let mut error = AccessTokenError::default();
166 error.set_type(AccessTokenErrorType::InvalidClient);
167 let mut json = ErrorDescription { error };
168 let mut response = self.endpoint.inner.response(
169 &mut request,
170 InnerTemplate::Unauthorized {
171 error: None,
172 access_token_error: Some(json.description()),
173 }
174 .into(),
175 )?;
176 response
177 .client_error()
178 .map_err(|err| self.endpoint.inner.web_error(err))?;
179 response
180 .body_json(&json.to_json())
181 .map_err(|err| self.endpoint.inner.web_error(err))?;
182 return Ok(response);
183 }
184 };
185
186 let token = match pending.issue(&mut self.endpoint, owner_id, self.allow_refresh_token) {
187 Err(error) => {
188 return client_credentials_error(&mut self.endpoint.inner, &mut request, error)
189 }
190 Ok(token) => token,
191 };
192
193 let mut response = self
194 .endpoint
195 .inner
196 .response(&mut request, InnerTemplate::Ok.into())?;
197 response
198 .body_json(&token.to_json())
199 .map_err(|err| self.endpoint.inner.web_error(err))?;
200 Ok(response)
201 }
202}
203
204fn client_credentials_error<E: Endpoint<R>, R: WebRequest>(
205 endpoint: &mut E, request: &mut R, error: ClientCredentialsError,
206) -> Result<R::Response, E::Error> {
207 Ok(match error {
208 ClientCredentialsError::Ignore => return Err(endpoint.error(OAuthError::DenySilently)),
209 ClientCredentialsError::Invalid(mut json) => {
210 let mut response = endpoint.response(
211 request,
212 InnerTemplate::BadRequest {
213 access_token_error: Some(json.description()),
214 }
215 .into(),
216 )?;
217 response.client_error().map_err(|err| endpoint.web_error(err))?;
218 response
219 .body_json(&json.to_json())
220 .map_err(|err| endpoint.web_error(err))?;
221 response
222 }
223 ClientCredentialsError::Unauthorized(mut json, scheme) => {
224 let mut response = endpoint.response(
225 request,
226 InnerTemplate::Unauthorized {
227 error: None,
228 access_token_error: Some(json.description()),
229 }
230 .into(),
231 )?;
232 response
233 .unauthorized(&scheme)
234 .map_err(|err| endpoint.web_error(err))?;
235 response
236 .body_json(&json.to_json())
237 .map_err(|err| endpoint.web_error(err))?;
238 response
239 }
240 ClientCredentialsError::Primitive(_) => {
241 return Err(endpoint.error(OAuthError::PrimitiveError));
243 }
244 })
245}
246
247impl<E: Endpoint<R>, R: WebRequest> ClientCredentialsEndpoint for WrappedToken<E, R> {
248 fn registrar(&self) -> &dyn Registrar {
249 self.inner.registrar().unwrap()
250 }
251
252 fn issuer(&mut self) -> &mut dyn Issuer {
253 self.inner.issuer_mut().unwrap()
254 }
255
256 fn extension(&mut self) -> &mut dyn Extension {
257 self.inner
258 .extension()
259 .and_then(super::Extension::client_credentials)
260 .unwrap_or(&mut self.extension_fallback)
261 }
262}
263
264impl<'a, R: WebRequest + 'a> WrappedRequest<'a, R> {
265 pub fn new(request: &'a mut R, credentials: bool) -> Self {
266 Self::new_or_fail(request, credentials).unwrap_or_else(Self::from_err)
267 }
268
269 fn new_or_fail(request: &'a mut R, credentials: bool) -> Result<Self, FailParse<R::Error>> {
270 let authorization = match request.authheader() {
272 Err(err) => return Err(FailParse::Err(err)),
273 Ok(Some(header)) => Self::parse_header(header).map(Some)?,
274 Ok(None) => None,
275 };
276
277 Ok(WrappedRequest {
278 request: PhantomData,
279 body: request.urlbody().map_err(FailParse::Err)?,
280 authorization,
281 error: None,
282 allow_credentials_in_body: credentials,
283 })
284 }
285
286 fn from_err(err: FailParse<R::Error>) -> Self {
287 WrappedRequest {
288 request: PhantomData,
289 body: Cow::Owned(Default::default()),
290 authorization: None,
291 error: Some(err),
292 allow_credentials_in_body: false,
293 }
294 }
295
296 fn parse_header(header: Cow<str>) -> Result<Authorization, Invalid> {
297 let authorization = {
298 let auth_data = match is_authorization_method(&header, "Basic ") {
299 None => return Err(Invalid),
300 Some(data) => data,
301 };
302
303 let combined = match STANDARD.decode(auth_data) {
304 Err(_) => return Err(Invalid),
305 Ok(vec) => vec,
306 };
307
308 let mut split = combined.splitn(2, |&c| c == b':');
309 let client_bin = match split.next() {
310 None => return Err(Invalid),
311 Some(client) => client,
312 };
313 let passwd = match split.next() {
314 None => return Err(Invalid),
315 Some(passwd64) => passwd64,
316 };
317
318 let client = match from_utf8(client_bin) {
319 Err(_) => return Err(Invalid),
320 Ok(client) => client,
321 };
322
323 Authorization(client.to_string(), passwd.to_vec())
324 };
325
326 Ok(authorization)
327 }
328}
329
330impl<'a, R: WebRequest> ClientCredentialsRequest for WrappedRequest<'a, R> {
331 fn valid(&self) -> bool {
332 self.error.is_none()
333 }
334
335 fn authorization(&self) -> Option<(Cow<str>, Cow<[u8]>)> {
336 self.authorization
337 .as_ref()
338 .map(|auth| (auth.0.as_str().into(), auth.1.as_slice().into()))
339 }
340
341 fn grant_type(&self) -> Option<Cow<str>> {
342 self.body.unique_value("grant_type")
343 }
344
345 fn scope(&self) -> Option<Cow<str>> {
346 self.body.unique_value("scope")
347 }
348
349 fn extension(&self, key: &str) -> Option<Cow<str>> {
350 self.body.unique_value(key)
351 }
352
353 fn allow_credentials_in_body(&self) -> bool {
354 self.allow_credentials_in_body
355 }
356}
357
358impl<E> From<Invalid> for FailParse<E> {
359 fn from(_: Invalid) -> Self {
360 FailParse::Invalid
361 }
362}