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