1use std::mem;
3use std::borrow::Cow;
4
5use chrono::{Utc, Duration};
6
7use crate::code_grant::accesstoken::BearerToken;
8use crate::code_grant::error::{AccessTokenError, AccessTokenErrorType};
9use crate::endpoint::{Scope, Solicitation};
10use crate::primitives::issuer::Issuer;
11use crate::primitives::grant::{Extensions, Grant};
12use crate::primitives::registrar::{Registrar, RegistrarError, BoundClient, PreGrant, ClientUrl};
13
14use super::accesstoken::{ErrorDescription, PrimitiveError};
15
16pub trait Request {
18 fn valid(&self) -> bool;
23
24 fn authorization(&self) -> Option<(Cow<str>, Cow<[u8]>)>;
26
27 fn scope(&self) -> Option<Cow<str>>;
29
30 fn grant_type(&self) -> Option<Cow<str>>;
32
33 fn extension(&self, key: &str) -> Option<Cow<str>>;
35
36 fn allow_credentials_in_body(&self) -> bool {
44 false
45 }
46
47 fn allow_refresh_token(&self) -> bool {
58 false
59 }
60}
61
62pub trait Extension {
66 fn extend(&mut self, request: &dyn Request) -> std::result::Result<Extensions, ()>;
68}
69
70impl Extension for () {
71 fn extend(&mut self, _: &dyn Request) -> std::result::Result<Extensions, ()> {
72 Ok(Extensions::new())
73 }
74}
75
76pub trait Endpoint {
82 fn registrar(&self) -> &dyn Registrar;
84
85 fn issuer(&mut self) -> &mut dyn Issuer;
87
88 fn extension(&mut self) -> &mut dyn Extension;
92}
93
94enum Credentials<'a> {
95 None,
97 Authenticated {
99 client_id: &'a str,
100 passphrase: &'a [u8],
101 },
102 Unauthenticated,
107 Duplicate,
111}
112
113pub struct ClientCredentials {
138 state: ClientCredentialsState,
139 scope: Option<Scope>,
140}
141
142enum ClientCredentialsState {
144 Authenticate {
145 client: String,
146 passdata: Vec<u8>,
147 },
148 Binding {
149 client_id: String,
150 },
151 Extend {
152 bound_client: BoundClient<'static>,
153 },
154 Negotiating {
155 bound_client: BoundClient<'static>,
156 extensions: Extensions,
157 },
158 Issue {
159 pre_grant: PreGrant,
160 extensions: Extensions,
161 },
162 Err(Error),
163}
164
165pub enum Input {
167 Authenticated,
169 Bound {
171 bound_client: BoundClient<'static>,
173 },
174 Extended {
176 extensions: Extensions,
178 },
179 Negotiated {
181 pre_grant: PreGrant,
183 },
184 None,
186}
187
188pub enum Output<'machine> {
194 Authenticate {
199 client: &'machine str,
201 passdata: &'machine [u8],
203 },
204 Binding {
210 client_id: &'machine str,
212 },
213 Extend,
217 Negotiate {
221 bound_client: &'machine BoundClient<'static>,
223 scope: Option<Scope>,
225 },
226 Ok {
231 pre_grant: &'machine PreGrant,
233 extensions: &'machine Extensions,
235 },
236 Err(Box<Error>),
240}
241
242impl ClientCredentials {
243 pub fn new(request: &dyn Request) -> Self {
245 let (state, scope) =
246 Self::validate(request).unwrap_or_else(|err| (ClientCredentialsState::Err(err), None));
247 ClientCredentials { state, scope }
248 }
249
250 pub fn advance(&mut self, input: Input) -> Output<'_> {
252 self.state = match (self.take(), input) {
253 (current, Input::None) => current,
254 (ClientCredentialsState::Authenticate { client, .. }, Input::Authenticated) => {
255 Self::authenticated(client)
256 }
257 (ClientCredentialsState::Binding { .. }, Input::Bound { bound_client }) => {
258 Self::bound(bound_client)
259 }
260 (ClientCredentialsState::Extend { bound_client }, Input::Extended { extensions }) => {
261 Self::extended(bound_client, extensions)
262 }
263 (
264 ClientCredentialsState::Negotiating { extensions, .. },
265 Input::Negotiated { pre_grant },
266 ) => Self::negotiated(pre_grant, extensions),
267 (ClientCredentialsState::Err(err), _) => ClientCredentialsState::Err(err),
268 (_, _) => ClientCredentialsState::Err(Error::Primitive(Box::new(PrimitiveError::empty()))),
269 };
270
271 self.output()
272 }
273
274 fn output(&self) -> Output<'_> {
275 match &self.state {
276 ClientCredentialsState::Err(err) => Output::Err(Box::new(err.clone())),
277 ClientCredentialsState::Authenticate { client, passdata, .. } => Output::Authenticate {
278 client,
279 passdata: passdata.as_slice(),
280 },
281 ClientCredentialsState::Binding { client_id } => Output::Binding { client_id },
282 ClientCredentialsState::Extend { .. } => Output::Extend,
283 ClientCredentialsState::Negotiating { bound_client, .. } => Output::Negotiate {
284 bound_client,
285 scope: self.scope.clone(),
286 },
287 ClientCredentialsState::Issue {
288 pre_grant,
289 extensions,
290 } => Output::Ok {
291 pre_grant,
292 extensions,
293 },
294 }
295 }
296
297 fn take(&mut self) -> ClientCredentialsState {
298 mem::replace(
299 &mut self.state,
300 ClientCredentialsState::Err(Error::Primitive(Box::new(PrimitiveError::empty()))),
301 )
302 }
303
304 fn validate(request: &dyn Request) -> Result<(ClientCredentialsState, Option<Scope>)> {
305 if !request.valid() {
306 return Err(Error::invalid());
307 }
308
309 let authorization = request.authorization();
310 let client_id = request.extension("client_id");
311 let client_secret = request.extension("client_secret");
312
313 let mut credentials = Credentials::None;
314 if let Some((client_id, auth)) = &authorization {
315 credentials.authenticate(client_id.as_ref(), auth.as_ref());
316 }
317
318 match (&client_id, &client_secret) {
319 (Some(client_id), Some(client_secret)) if request.allow_credentials_in_body() => {
320 credentials.authenticate(client_id.as_ref(), client_secret.as_ref().as_bytes())
321 }
322 (None, None) => {}
323 _ => credentials.unauthenticated(),
324 }
325
326 let scope = match request.scope().map(|scope| scope.as_ref().parse()) {
327 None => None,
328 Some(Err(_)) => return Err(Error::invalid()),
329 Some(Ok(scope)) => Some(scope),
330 };
331
332 match request.grant_type() {
333 Some(ref cow) if cow == "client_credentials" => (),
334 None => return Err(Error::invalid()),
335 Some(_) => return Err(Error::invalid_with(AccessTokenErrorType::UnsupportedGrantType)),
336 };
337
338 let (client_id, passdata) = credentials.into_client().ok_or_else(Error::invalid)?;
339
340 Ok((
341 ClientCredentialsState::Authenticate {
342 client: client_id.to_string(),
343 passdata: Vec::from(passdata),
344 },
345 scope,
346 ))
347 }
348
349 fn authenticated(client_id: String) -> ClientCredentialsState {
350 ClientCredentialsState::Binding { client_id }
351 }
352
353 fn bound(bound_client: BoundClient<'static>) -> ClientCredentialsState {
354 ClientCredentialsState::Extend { bound_client }
355 }
356
357 fn extended(bound_client: BoundClient<'static>, extensions: Extensions) -> ClientCredentialsState {
358 ClientCredentialsState::Negotiating {
359 bound_client,
360 extensions,
361 }
362 }
363
364 fn negotiated(pre_grant: PreGrant, extensions: Extensions) -> ClientCredentialsState {
365 ClientCredentialsState::Issue {
366 pre_grant,
367 extensions,
368 }
369 }
370}
371
372pub struct Pending {
381 pre_grant: PreGrant,
382 extensions: Extensions,
383}
384
385impl Pending {
386 pub fn as_solicitation(&self) -> Solicitation<'_> {
388 Solicitation {
389 grant: Cow::Borrowed(&self.pre_grant),
390 state: None,
391 }
392 }
393
394 pub fn issue(
399 self, handler: &mut dyn Endpoint, owner_id: String, allow_refresh_token: bool,
400 ) -> Result<BearerToken> {
401 let mut token = handler
402 .issuer()
403 .issue(Grant {
404 owner_id,
405 client_id: self.pre_grant.client_id,
406 redirect_uri: self.pre_grant.redirect_uri.into_url(),
407 scope: self.pre_grant.scope.clone(),
408 until: Utc::now() + Duration::minutes(10),
409 extensions: self.extensions,
410 })
411 .map_err(|()| Error::Primitive(Box::new(PrimitiveError::empty())))?;
412
413 if !allow_refresh_token {
414 token.refresh = None;
415 }
416
417 Ok(BearerToken(token, self.pre_grant.scope.clone()))
418 }
419}
420
421pub fn client_credentials(handler: &mut dyn Endpoint, request: &dyn Request) -> Result<Pending> {
424 enum Requested {
425 None,
426 Authenticate {
427 client: String,
428 passdata: Vec<u8>,
429 },
430 Bind {
431 client_id: String,
432 },
433 Extend,
434 Negotiate {
435 bound_client: BoundClient<'static>,
436 scope: Option<Scope>,
437 },
438 }
439
440 let mut client_credentials = ClientCredentials::new(request);
441 let mut requested = Requested::None;
442
443 loop {
444 let input = match requested {
445 Requested::None => Input::None,
446 Requested::Authenticate { client, passdata } => {
447 handler
448 .registrar()
449 .check(&client, Some(passdata.as_slice()))
450 .map_err(|err| match err {
451 RegistrarError::Unspecified => Error::unauthorized("basic"),
452 RegistrarError::PrimitiveError => Error::Primitive(Box::new(PrimitiveError {
453 grant: None,
454 extensions: None,
455 })),
456 })?;
457 Input::Authenticated
458 }
459 Requested::Bind { client_id } => {
460 let client_url = ClientUrl {
461 client_id: Cow::Owned(client_id),
462 redirect_uri: None,
463 };
464 let bound_client = match handler.registrar().bound_redirect(client_url) {
465 Err(RegistrarError::Unspecified) => return Err(Error::Ignore),
466 Err(RegistrarError::PrimitiveError) => {
467 return Err(Error::Primitive(Box::new(PrimitiveError {
468 grant: None,
469 extensions: None,
470 })));
471 }
472 Ok(pre_grant) => pre_grant,
473 };
474 Input::Bound { bound_client }
475 }
476 Requested::Extend => {
477 let extensions = handler
478 .extension()
479 .extend(request)
480 .map_err(|_| Error::invalid())?;
481 Input::Extended { extensions }
482 }
483 Requested::Negotiate { bound_client, scope } => {
484 let pre_grant = handler
485 .registrar()
486 .negotiate(bound_client.clone(), scope.clone())
487 .map_err(|err| match err {
488 RegistrarError::PrimitiveError => Error::Primitive(Box::new(PrimitiveError {
489 grant: None,
490 extensions: None,
491 })),
492 RegistrarError::Unspecified => Error::Ignore,
493 })?;
494 Input::Negotiated { pre_grant }
495 }
496 };
497
498 requested = match client_credentials.advance(input) {
499 Output::Authenticate { client, passdata } => Requested::Authenticate {
500 client: client.to_owned(),
501 passdata: passdata.to_vec(),
502 },
503 Output::Binding { client_id } => Requested::Bind {
504 client_id: client_id.to_owned(),
505 },
506 Output::Extend => Requested::Extend,
507 Output::Negotiate { bound_client, scope } => Requested::Negotiate {
508 bound_client: bound_client.clone(),
509 scope,
510 },
511 Output::Ok {
512 pre_grant,
513 extensions,
514 } => {
515 return Ok(Pending {
516 pre_grant: pre_grant.clone(),
517 extensions: extensions.clone(),
518 })
519 }
520 Output::Err(e) => return Err(*e),
521 };
522 }
523}
524
525impl<'a> Credentials<'a> {
526 pub fn authenticate(&mut self, client_id: &'a str, passphrase: &'a [u8]) {
527 self.add(Credentials::Authenticated {
528 client_id,
529 passphrase,
530 })
531 }
532
533 pub fn unauthenticated(&mut self) {
534 self.add(Credentials::Unauthenticated)
535 }
536
537 pub fn into_client(self) -> Option<(&'a str, &'a [u8])> {
538 match self {
539 Credentials::Authenticated {
540 client_id,
541 passphrase,
542 } => Some((client_id, passphrase)),
543 Credentials::Unauthenticated { .. } => None,
544 _ => None,
545 }
546 }
547
548 fn add(&mut self, new: Self) {
549 *self = match self {
550 Credentials::None => new,
551 _ => Credentials::Duplicate,
552 };
553 }
554}
555
556#[derive(Clone)]
558pub enum Error {
559 Ignore,
561
562 Invalid(ErrorDescription),
564
565 Unauthorized(ErrorDescription, String),
567
568 Primitive(Box<PrimitiveError>),
573}
574
575type Result<T> = std::result::Result<T, Error>;
576
577impl Error {
578 pub fn invalid() -> Self {
580 Error::Invalid(ErrorDescription {
581 error: AccessTokenError::default(),
582 })
583 }
584
585 fn invalid_with(with_type: AccessTokenErrorType) -> Self {
586 Error::Invalid(ErrorDescription {
587 error: {
588 let mut error = AccessTokenError::default();
589 error.set_type(with_type);
590 error
591 },
592 })
593 }
594
595 pub fn unauthorized(authtype: &str) -> Error {
597 Error::Unauthorized(
598 ErrorDescription {
599 error: {
600 let mut error = AccessTokenError::default();
601 error.set_type(AccessTokenErrorType::InvalidClient);
602 error
603 },
604 },
605 authtype.to_string(),
606 )
607 }
608
609 pub fn description(&mut self) -> Option<&mut AccessTokenError> {
614 match self {
615 Error::Ignore => None,
616 Error::Invalid(description) => Some(description.description()),
617 Error::Unauthorized(description, _) => Some(description.description()),
618 Error::Primitive(_) => None,
619 }
620 }
621}