diff --git a/Migration.md b/Migration.md index efcb05c9..019338b5 100644 --- a/Migration.md +++ b/Migration.md @@ -50,9 +50,9 @@ replicate the old behaviour, its body should simply consist of `Err(())`. ## v0.4.5 -An empty `refresh` token in the `IssuedToken` will no longer inidicate support +An empty `refresh` token in the `IssuedToken` will no longer indicate support for refreshing to the client. Furthermore, refresh tokens need to be -explicitely enabled for `TokenSigner` as there is no good way to revoke them +explicitly enabled for `TokenSigner` as there is no good way to revoke them and are mostly intended for usage in custom signers. ## v0.4.1 @@ -66,7 +66,7 @@ larger code bases would be implementing `endpoint::Endpoint` yourself. Note that `MethodAuthorizer` got replaced by `frontends::simple::FnSolicitor` and the `IronAuthorizer` has been fully removed. `SimpleAuthorization` was -superseeded by `endpoint::OwnerAuthorization`. +superseded by `endpoint::OwnerAuthorization`. Support for a Bearer token authorizing Middleware implementation has not yet been implemented. Also, see the notes on `QueryParamter` and module reordering @@ -94,7 +94,7 @@ multiple independent extensions at the same time, this is no longer required for other frontends. The data portion of a `GrantExtension` has been renamed to the more unique `Value`, and the `simple` extension module extends on this trait to offer `AccessTokenAddon` and `AuthorizationAddon`, simple traits to -implement only a portion of a fullblown system of extension at a time. +implement only a portion of a full-blown system of extension at a time. Serde support for `NormalizedParameter` so that there is less confusion about how to construct them and the potential pitfalls of dropping duplicate @@ -171,7 +171,7 @@ The following names have changed for consistency: ### Actix frontend The standardization of a simple, reusable `Endpoint` offers exiting new -possibilites. Foremost, a simple newtype wrapper around this and other +possibilities. Foremost, a simple newtype wrapper around this and other primitives imbues them with `Actor` powers and messaging. Requests and responses are now more composable so the former now has a simpler representation and the necessity of tacking on owner owner consent information @@ -184,7 +184,7 @@ The initial construction of a `OAuthRequest` is now the result of an the actix message constructors. Since `OAuthRequest` now also implements `WebRequest` in a simple manner, many implementors will likely want to use a newtype style to further customize error types and response representations. -Keep in mind that for a request to be useable as a message to an endpoint +Keep in mind that for a request to be usable as a message to an endpoint actor, the error types of the two have to agree. This restriction may be lifted in later versions. @@ -337,7 +337,7 @@ of the endpoint does that conversion. Rationale: The trait bounds puts some restrictions on implementing endpoints with error types that are not defined in the current trait. Additionally, it made it impossible to generalize over the underlying request type, as there is -no way to implemention `impl From for ErrorType`, of course. +no way to implement `impl From for ErrorType`, of course. ---- @@ -349,7 +349,7 @@ traits `AuthorizationExtension` etc. have been moved to the new frontend. Rationale: This is to allow groups of extensions working closely together, such -as possibly for OpenID in the future. It also solves a few efficieny and design +as possibly for OpenID in the future. It also solves a few efficient and design issues by leaving the representation more open to library users/frontends. Since extension do not provide guarantees on idempotency, they can not be simply retried. Therefore, the asynchronous interface of actix can not diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md index 5e365ab7..b567fc11 100644 --- a/docs/CONTRIBUTING.md +++ b/docs/CONTRIBUTING.md @@ -7,7 +7,7 @@ easiest way to track its progress is by opening a tracking issue. In case you already have working code - even better. Simply link the pull request in the issue. If you have not done so already, you _may_ also add -yourself to the [list of constributors][contributors] (that's up to You, there +yourself to the [list of contributors][contributors] (that's up to You, there is no need to so). Please respect that I maintain this on my own currently and have limited time. diff --git a/examples/support/generic.rs b/examples/support/generic.rs index 2700b993..13304355 100644 --- a/examples/support/generic.rs +++ b/examples/support/generic.rs @@ -1,7 +1,7 @@ //! Helper methods for several examples. //! //! The support files for each frontend include a client instance for several implemented -//! frontends. These are not part of the main example code as this library focusses purely on the +//! frontends. These are not part of the main example code as this library focuses purely on the //! server side. This module contains code that can be shared between the different frontends. //! Since we want to be able to run the actix example but share it with rocket examples but //! rocket includes macros in its crate root, the module include order is a bit strange. @@ -11,7 +11,7 @@ #![allow(unused)] /// Simplistic reqwest client. -#[path="./client.rs"] +#[path = "./client.rs"] mod client; use oxide_auth::endpoint::Solicitation; @@ -39,11 +39,14 @@ pub fn open_in_browser() { Err(Error::new(ErrorKind::Other, "Open not supported")) }; - open_with.and_then(|cmd| Command::new(cmd).arg(target_addres).status()) - .and_then(|status| if status.success() { - Ok(()) - } else { - Err(Error::new(ErrorKind::Other, "Non zero status")) + open_with + .and_then(|cmd| Command::new(cmd).arg(target_addres).status()) + .and_then(|status| { + if status.success() { + Ok(()) + } else { + Err(Error::new(ErrorKind::Other, "Non zero status")) + } }) .unwrap_or_else(|_| println!("Please navigate to {}", target_addres)); } @@ -51,7 +54,7 @@ pub fn open_in_browser() { pub fn consent_page_html(route: &str, solicitation: Solicitation) -> String { macro_rules! template { () => { -"'{0:}' (at {1:}) is requesting permission for '{2:}' + "'{0:}' (at {1:}) is requesting permission for '{2:}'
@@ -72,8 +75,9 @@ pub fn consent_page_html(route: &str, solicitation: Solicitation) -> String { if let Some(state) = state { extra.push(("state", state)); } - - format!(template!(), + + format!( + template!(), grant.client_id, grant.redirect_uri, grant.scope, diff --git a/oxide-auth-actix/Cargo.toml b/oxide-auth-actix/Cargo.toml index 0aa1562c..4567cb67 100644 --- a/oxide-auth-actix/Cargo.toml +++ b/oxide-auth-actix/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "oxide-auth-actix" -version = "0.2.0" +version = "0.3.0" authors = ["Andreas Molzer "] repository = "https://github.com/HeroicKatora/oxide-auth.git" @@ -15,7 +15,7 @@ edition = "2018" actix = { version = "0.12", default-features = false } actix-web = { version = "4.0.1", default-features = false } futures = "0.3" -oxide-auth = { version = "0.5.0", path = "../oxide-auth" } +oxide-auth = { version = "0.6", path = "../oxide-auth" } serde_urlencoded = "0.7" url = "2" diff --git a/oxide-auth-actix/Changes.md b/oxide-auth-actix/Changes.md index 0e95a616..69755375 100644 --- a/oxide-auth-actix/Changes.md +++ b/oxide-auth-actix/Changes.md @@ -1,3 +1,7 @@ +## 0.3.0 +- Fixed clippy errors +- Turned some `Into` implementations into `From` implementations + ## 0.2.0 - Now compatible to `actix = "4"`. diff --git a/oxide-auth-actix/examples/actix-example/Cargo.toml b/oxide-auth-actix/examples/actix-example/Cargo.toml index 0d96cfaf..77fd3f4f 100644 --- a/oxide-auth-actix/examples/actix-example/Cargo.toml +++ b/oxide-auth-actix/examples/actix-example/Cargo.toml @@ -9,8 +9,8 @@ actix = "0.12" actix-web = "4.0.1" env_logger = "0.7" futures = "0.3" -oxide-auth = { version = "0.5.0", path = "./../../../oxide-auth" } -oxide-auth-actix = { version = "0.2.0", path = "./../../" } +oxide-auth = { version = "0.6", path = "./../../../oxide-auth" } +oxide-auth-actix = { version = "0.3.0", path = "./../../../oxide-auth-actix" } reqwest = "=0.9.5" serde = "1.0" serde_json = "1.0" diff --git a/oxide-auth-actix/examples/actix-example/src/main.rs b/oxide-auth-actix/examples/actix-example/src/main.rs index f2510368..dd23eac5 100644 --- a/oxide-auth-actix/examples/actix-example/src/main.rs +++ b/oxide-auth-actix/examples/actix-example/src/main.rs @@ -24,15 +24,17 @@ here to begin the authorization process. "; +pub type GenericEndpoint = Generic< + ClientMap, + AuthMap, + TokenMap, + Vacant, + Vec, + fn() -> OAuthResponse, +>; + struct State { - endpoint: Generic< - ClientMap, - AuthMap, - TokenMap, - Vacant, - Vec, - fn() -> OAuthResponse, - >, + endpoint: GenericEndpoint, } enum Extras { @@ -42,7 +44,7 @@ enum Extras { } async fn get_authorize( - (req, state): (OAuthRequest, web::Data>), + (req, state): (OAuthRequest, Data>), ) -> Result { // GET requests should not mutate server state and are extremely // vulnerable accidental repetition as well as Cross-Site Request @@ -51,7 +53,7 @@ async fn get_authorize( } async fn post_authorize( - (r, req, state): (HttpRequest, OAuthRequest, web::Data>), + (r, req, state): (HttpRequest, OAuthRequest, Data>), ) -> Result { // Some authentication should be performed here in production cases state @@ -59,19 +61,15 @@ async fn post_authorize( .await? } -async fn token((req, state): (OAuthRequest, web::Data>)) -> Result { +async fn token((req, state): (OAuthRequest, Data>)) -> Result { state.send(Token(req).wrap(Extras::Nothing)).await? } -async fn refresh( - (req, state): (OAuthRequest, web::Data>), -) -> Result { +async fn refresh((req, state): (OAuthRequest, Data>)) -> Result { state.send(Refresh(req).wrap(Extras::Nothing)).await? } -async fn index( - (req, state): (OAuthResource, web::Data>), -) -> Result { +async fn index((req, state): (OAuthResource, Data>)) -> Result { match state .send(Resource(req.into_request()).wrap(Extras::Nothing)) .await? @@ -84,7 +82,7 @@ async fn index( } } -async fn start_browser() -> () { +async fn start_browser() { let _ = thread::spawn(support::open_in_browser); } @@ -161,9 +159,9 @@ impl State { } } - pub fn with_solicitor<'a, S>( - &'a mut self, solicitor: S, - ) -> impl Endpoint + 'a + pub fn with_solicitor( + &'_ mut self, solicitor: S, + ) -> impl Endpoint + '_ where S: OwnerSolicitor + 'static, { @@ -200,7 +198,7 @@ where OAuthResponse::ok() .content_type("text/html") .unwrap() - .body(&crate::support::consent_page_html("/authorize".into(), pre_grant)), + .body(&support::consent_page_html("/authorize", pre_grant)), ) }); diff --git a/oxide-auth-actix/examples/actix-example/src/support.rs b/oxide-auth-actix/examples/actix-example/src/support.rs index 3337b925..b95d4494 100644 --- a/oxide-auth-actix/examples/actix-example/src/support.rs +++ b/oxide-auth-actix/examples/actix-example/src/support.rs @@ -38,7 +38,7 @@ pub fn dummy_client() -> dev::Server { } async fn endpoint_impl( - (query, state): (web::Query>, web::Data), + (query, state): (web::Query>, Data), ) -> impl Responder { if let Some(cause) = query.get("error") { return HttpResponse::BadRequest() @@ -56,14 +56,14 @@ async fn endpoint_impl( } } -async fn refresh(state: web::Data) -> impl Responder { +async fn refresh(state: Data) -> impl Responder { match state.refresh() { Ok(()) => HttpResponse::Found().append_header(("Location", "/")).finish(), Err(err) => HttpResponse::InternalServerError().body(format!("{}", err)), } } -async fn get_with_token(state: web::Data) -> impl Responder { +async fn get_with_token(state: Data) -> impl Responder { let protected_page = match state.retrieve_protected_page() { Ok(page) => page, Err(err) => return HttpResponse::InternalServerError().body(format!("{}", err)), diff --git a/oxide-auth-actix/src/lib.rs b/oxide-auth-actix/src/lib.rs index 783ea046..78829df0 100644 --- a/oxide-auth-actix/src/lib.rs +++ b/oxide-auth-actix/src/lib.rs @@ -149,10 +149,10 @@ pub struct OAuthResponse { #[derive(Debug)] /// The error type for Oxide Auth operations pub enum WebError { - /// Errors occuring in Endpoint operations + /// Errors occurring in Endpoint operations Endpoint(OAuthError), - /// Errors occuring when producing Headers + /// Errors occurring when producing Headers Header(InvalidHeaderValue), /// Errors with the request encoding @@ -447,8 +447,10 @@ impl fmt::Display for WebError { WebError::Authorization => write!(f, "Request has invalid Authorization headers"), WebError::Canceled => write!(f, "Operation canceled"), WebError::Mailbox => write!(f, "An actor's mailbox was full"), - WebError::InternalError(None) => write!(f, "An internal server error occured"), - WebError::InternalError(Some(ref e)) => write!(f, "An internal server error occured: {}", e), + WebError::InternalError(None) => write!(f, "An internal server error occurred"), + WebError::InternalError(Some(ref e)) => { + write!(f, "An internal server error occurred: {}", e) + } } } } diff --git a/oxide-auth-async/Cargo.toml b/oxide-auth-async/Cargo.toml index 32c25563..849fa9ea 100644 --- a/oxide-auth-async/Cargo.toml +++ b/oxide-auth-async/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "oxide-auth-async" -version = "0.1.0" +version = "0.3.0" authors = ["Andreas Molzer "] repository = "https://github.com/HeroicKatora/oxide-auth.git" @@ -13,7 +13,7 @@ edition = "2018" [dependencies] async-trait = "0.1.21" -oxide-auth = { version = "0.5.0", path = "../oxide-auth" } +oxide-auth = { version = "0.6", path = "../oxide-auth" } base64 = "0.12" url = "2" chrono = "0.4.2" diff --git a/oxide-auth-async/src/code_grant.rs b/oxide-auth-async/src/code_grant.rs index 5222463e..0636515e 100644 --- a/oxide-auth-async/src/code_grant.rs +++ b/oxide-auth-async/src/code_grant.rs @@ -131,7 +131,7 @@ pub mod resource { pub mod access_token { use async_trait::async_trait; use oxide_auth::{ - code_grant::accesstoken::{ + code_grant::access_token::{ AccessToken, BearerToken, Error, Input, Output, PrimitiveError, Request as TokenRequest, }, primitives::{ @@ -149,14 +149,14 @@ pub mod access_token { /// authorization code request. async fn extend( &mut self, request: &(dyn TokenRequest + Sync), data: Extensions, - ) -> std::result::Result; + ) -> Result; } #[async_trait] impl Extension for () { async fn extend( &mut self, _: &(dyn TokenRequest + Sync), _: Extensions, - ) -> std::result::Result { + ) -> Result { Ok(Extensions::new()) } } @@ -286,14 +286,12 @@ pub mod authorization { #[async_trait] pub trait Extension { /// Inspect the request to produce extension data. - async fn extend( - &mut self, request: &(dyn Request + Sync), - ) -> std::result::Result; + async fn extend(&mut self, request: &(dyn Request + Sync)) -> Result; } #[async_trait] impl Extension for () { - async fn extend(&mut self, _: &(dyn Request + Sync)) -> std::result::Result { + async fn extend(&mut self, _: &(dyn Request + Sync)) -> Result { Ok(Extensions::new()) } } @@ -317,7 +315,7 @@ pub mod authorization { } /// Represents a valid, currently pending authorization request not bound to an owner. The frontend - /// can signal a reponse using this object. + /// can signal a response using this object. #[derive(Clone)] pub struct Pending { pre_grant: PreGrant, @@ -382,7 +380,7 @@ pub mod authorization { /// Retrieve allowed scope and redirect url from the registrar. /// - /// Checks the validity of any given input as the registrar instance communicates the registrated + /// Checks the validity of any given input as the registrar instance communicates the registered /// parameters. The registrar can also set or override the requested (default) scope of the client. /// This will result in a tuple of negotiated parameters which can be used further to authorize /// the client by the owner or, in case of errors, in an action to be taken. diff --git a/oxide-auth-async/src/endpoint/access_token.rs b/oxide-auth-async/src/endpoint/access_token.rs index 3f7e518b..2f8b5f61 100644 --- a/oxide-auth-async/src/endpoint/access_token.rs +++ b/oxide-auth-async/src/endpoint/access_token.rs @@ -3,7 +3,7 @@ use std::{borrow::Cow, marker::PhantomData}; use oxide_auth::{ endpoint::{QueryParameter, WebRequest, OAuthError, WebResponse, Template, NormalizedParameter}, - code_grant::accesstoken::{Error as TokenError, Request as TokenRequest}, + code_grant::access_token::{Error as TokenError, Request as TokenRequest}, }; use super::Endpoint; @@ -21,7 +21,7 @@ use crate::{ /// /// Client credentials can be allowed to appear in the request body instead of being /// required to be passed as HTTP Basic authorization. This is not recommended and must be -/// enabled explicitely. See [`allow_credentials_in_body`] for details. +/// enabled explicitly. See [`allow_credentials_in_body`] for details. /// /// [`allow_credentials_in_body`]: #method.allow_credentials_in_body pub struct AccessTokenFlow @@ -114,7 +114,7 @@ where /// RECOMMENDED and need not be supported. The parameters MUST NOT appear in the request URI /// itself. /// - /// Thus support is disabled by default and must be explicitely enabled. + /// Thus support is disabled by default and must be explicitly enabled. pub fn allow_credentials_in_body(&mut self, allow: bool) { self.allow_credentials_in_body = allow; } diff --git a/oxide-auth-async/src/endpoint/authorization.rs b/oxide-auth-async/src/endpoint/authorization.rs index 029a598d..2cc71d0d 100644 --- a/oxide-auth-async/src/endpoint/authorization.rs +++ b/oxide-auth-async/src/endpoint/authorization.rs @@ -5,8 +5,11 @@ use oxide_auth::{ code_grant::authorization::{Error as AuthorizationError, Request as AuthorizationRequest}, }; -use crate::code_grant::authorization::{ - authorization_code, Endpoint as AuthorizationEndpoint, Extension, Pending, +use crate::{ + code_grant::authorization::{ + authorization_code, Endpoint as AuthorizationEndpoint, Extension, Pending, + }, + endpoint::OwnerSolicitor, }; use super::*; @@ -65,7 +68,7 @@ where inner: AuthorizationPartialInner<'a, E, R>, /// TODO: offer this in the public api instead of dropping the request. - _with_request: Option () + Send>>, + _with_request: Option>, } /// Result type from processing an authentication request. diff --git a/oxide-auth-async/src/endpoint/refresh.rs b/oxide-auth-async/src/endpoint/refresh.rs index 03e02d93..f41b1c1f 100644 --- a/oxide-auth-async/src/endpoint/refresh.rs +++ b/oxide-auth-async/src/endpoint/refresh.rs @@ -213,12 +213,6 @@ impl Request for WrappedRequest { self.body.unique_value("refresh_token") } - fn authorization(&self) -> Option<(Cow, Cow<[u8]>)> { - self.authorization - .as_ref() - .map(|auth| (auth.0.as_str().into(), auth.1.as_slice().into())) - } - fn scope(&self) -> Option> { self.body.unique_value("scope") } @@ -227,6 +221,12 @@ impl Request for WrappedRequest { self.body.unique_value("grant_type") } + fn authorization(&self) -> Option<(Cow, Cow<[u8]>)> { + self.authorization + .as_ref() + .map(|auth| (auth.0.as_str().into(), auth.1.as_slice().into())) + } + fn extension(&self, key: &str) -> Option> { self.body.unique_value(key) } diff --git a/oxide-auth-async/src/endpoint/resource.rs b/oxide-auth-async/src/endpoint/resource.rs index 2894bb91..2755f5fa 100644 --- a/oxide-auth-async/src/endpoint/resource.rs +++ b/oxide-auth-async/src/endpoint/resource.rs @@ -115,7 +115,7 @@ where impl WrappedRequest { fn new(request: &mut R) -> Self { let token = match request.authheader() { - // TODO: this is unecessarily wasteful, we always clone. + // TODO: this is unnecessarily wasteful, we always clone. Ok(Some(token)) => Some(token.into_owned()), Ok(None) => None, Err(error) => return Self::from_error(error), diff --git a/oxide-auth-async/src/primitives.rs b/oxide-auth-async/src/primitives.rs index e028b5e1..e56591e6 100644 --- a/oxide-auth-async/src/primitives.rs +++ b/oxide-auth-async/src/primitives.rs @@ -1,10 +1,13 @@ //! Async versions of all primitives traits. use async_trait::async_trait; -use oxide_auth::primitives::{grant::Grant, scope::Scope}; -use oxide_auth::primitives::issuer::{IssuedToken, RefreshedToken}; -use oxide_auth::primitives::{ - authorizer, registrar, issuer, - registrar::{ClientUrl, BoundClient, RegistrarError, PreGrant}, +use oxide_auth::{ + primitives::{ + grant::Grant, + scope::Scope, + issuer::{IssuedToken, RefreshedToken}, + authorizer, registrar, issuer, + registrar::{ClientUrl, BoundClient, RegistrarError, PreGrant}, + }, }; #[async_trait] @@ -65,6 +68,7 @@ where pub trait Registrar { async fn bound_redirect<'a>(&self, bound: ClientUrl<'a>) -> Result, RegistrarError>; + #[allow(clippy::needless_lifetimes)] // Clippy is wrong here, we need this lifetime. async fn negotiate<'a>( &self, client: BoundClient<'a>, scope: Option, ) -> Result; @@ -81,6 +85,7 @@ where registrar::Registrar::bound_redirect(self, bound) } + #[allow(clippy::needless_lifetimes)] async fn negotiate<'a>( &self, client: BoundClient<'a>, scope: Option, ) -> Result { diff --git a/oxide-auth-async/src/tests/access_token.rs b/oxide-auth-async/src/tests/access_token.rs index 228c1708..832008bc 100644 --- a/oxide-auth-async/src/tests/access_token.rs +++ b/oxide-auth-async/src/tests/access_token.rs @@ -1,26 +1,21 @@ -use oxide_auth::primitives::authorizer::AuthMap; -use oxide_auth::primitives::issuer::TokenMap; -use oxide_auth::primitives::grant::{Grant, Extensions}; use oxide_auth::{ + primitives::{ + authorizer::AuthMap, + issuer::TokenMap, + grant::{Grant, Extensions}, + registrar::{Client, ClientMap, RegisteredUrl}, + }, frontends::simple::endpoint::Error, - primitives::registrar::{Client, ClientMap, RegisteredUrl}, endpoint::WebRequest, }; - use crate::{ endpoint::{access_token::AccessTokenFlow, Endpoint}, primitives::Authorizer, }; -//use crate::frontends::simple::endpoint::access_token_flow; - use std::collections::HashMap; - -use base64; use chrono::{Utc, Duration}; -use serde_json; - -use super::{Body, CraftedRequest, CraftedResponse, Status, TestGenerator, ToSingleValueQuery}; -use super::defaults::*; +use crate::primitives::{Issuer, Registrar}; +use super::{Body, CraftedRequest, CraftedResponse, Status, TestGenerator, ToSingleValueQuery, defaults::*}; struct AccessTokenSetup { registrar: ClientMap, @@ -52,15 +47,23 @@ impl<'a> AccessTokenEndpoint<'a> { impl<'a> Endpoint for AccessTokenEndpoint<'a> { type Error = Error; - fn registrar(&self) -> Option<&(dyn crate::primitives::Registrar + Sync)> { + fn registrar(&self) -> Option<&(dyn Registrar + Sync)> { Some(self.registrar) } - fn authorizer_mut(&mut self) -> Option<&mut (dyn crate::primitives::Authorizer + Send)> { + fn authorizer_mut(&mut self) -> Option<&mut (dyn Authorizer + Send)> { Some(self.authorizer) } - fn issuer_mut(&mut self) -> Option<&mut (dyn crate::primitives::Issuer + Send)> { + fn issuer_mut(&mut self) -> Option<&mut (dyn Issuer + Send)> { Some(self.issuer) } + fn owner_solicitor( + &mut self, + ) -> Option<&mut (dyn crate::endpoint::OwnerSolicitor + Send)> { + None + } + fn scopes(&mut self) -> Option<&mut dyn oxide_auth::endpoint::Scopes> { + None + } fn response( &mut self, _: &mut CraftedRequest, _: oxide_auth::endpoint::Template, ) -> Result<::Response, Self::Error> { @@ -72,14 +75,6 @@ impl<'a> Endpoint for AccessTokenEndpoint<'a> { fn web_error(&mut self, _err: ::Error) -> Self::Error { unimplemented!() } - fn scopes(&mut self) -> Option<&mut dyn oxide_auth::endpoint::Scopes> { - None - } - fn owner_solicitor( - &mut self, - ) -> Option<&mut (dyn crate::endpoint::OwnerSolicitor + Send)> { - None - } } impl AccessTokenSetup { @@ -179,7 +174,7 @@ impl AccessTokenSetup { .unwrap(); match smol::run(access_token_flow.execute(request)) { Ok(ref response) => Self::assert_json_error_set(response), - resp => panic!("Expected non-error reponse, got {:?}", resp), + resp => panic!("Expected non-error response, got {:?}", resp), } } @@ -191,7 +186,7 @@ impl AccessTokenSetup { )) .unwrap(); let response = - smol::run(access_token_flow.execute(request)).expect("Expected non-error reponse"); + smol::run(access_token_flow.execute(request)).expect("Expected non-error response"); self.assert_ok_access_token(response); } @@ -256,7 +251,7 @@ fn access_valid_private() { setup.test_success(valid_public); } -// When creating a client from a preparsed url expect all equivalent urls to also be valid +// When creating a client from a prepared url expect all equivalent urls to also be valid // parameters for the redirect_uri. Partly because `Url` already does some normalization during // parsing. The RFC recommends string-based comparison when the 'client registration included the // full redirection URI'. When passing an URL however, for the moment the only way, this does not @@ -324,7 +319,7 @@ fn access_equivalent_url() { #[test] fn access_request_unknown_client() { let mut setup = AccessTokenSetup::private_client(); - // Trying to autenticate as some unknown client with the passphrase + // Trying to authenticate as some unknown client with the passphrase let unknown_client = CraftedRequest { query: None, urlbody: Some( @@ -348,7 +343,7 @@ fn access_request_unknown_client() { #[test] fn access_request_wrong_authentication() { let mut setup = AccessTokenSetup::private_client(); - // Trying to autenticate with an unsupported method (instead of Basic) + // Trying to authenticate with an unsupported method (instead of Basic) let wrong_authentication = CraftedRequest { query: None, urlbody: Some( @@ -369,7 +364,7 @@ fn access_request_wrong_authentication() { #[test] fn access_request_wrong_password() { let mut setup = AccessTokenSetup::private_client(); - // Trying to autenticate with the wrong password + // Trying to authenticate with the wrong password let wrong_password = CraftedRequest { query: None, urlbody: Some( @@ -393,7 +388,7 @@ fn access_request_wrong_password() { #[test] fn access_request_empty_password() { let mut setup = AccessTokenSetup::private_client(); - // Trying to autenticate with an empty password + // Trying to authenticate with an empty password let empty_password = CraftedRequest { query: None, urlbody: Some( @@ -414,7 +409,7 @@ fn access_request_empty_password() { #[test] fn access_request_multiple_client_indications() { let mut setup = AccessTokenSetup::private_client(); - // Trying to autenticate with an unsupported method (instead of Basic) + // Trying to authenticate with an unsupported method (instead of Basic) let multiple_client_indications = CraftedRequest { query: None, urlbody: Some( @@ -436,7 +431,7 @@ fn access_request_multiple_client_indications() { #[test] fn access_request_public_authorization() { let mut setup = AccessTokenSetup::public_client(); - // Trying to autenticate a public client + // Trying to authenticate a public client let public_authorization = CraftedRequest { query: None, urlbody: Some( @@ -457,7 +452,7 @@ fn access_request_public_authorization() { #[test] fn access_request_public_missing_client() { let mut setup = AccessTokenSetup::public_client(); - // Trying to autenticate with an unsupported method (instead of Basic) + // Trying to authenticate with an unsupported method (instead of Basic) let public_missing_client = CraftedRequest { query: None, urlbody: Some( @@ -478,7 +473,7 @@ fn access_request_public_missing_client() { #[test] fn access_request_invalid_basic() { let mut setup = AccessTokenSetup::private_client(); - // Trying to autenticate with an invalid basic authentication header + // Trying to authenticate with an invalid basic authentication header let invalid_basic = CraftedRequest { query: None, urlbody: Some( @@ -572,7 +567,7 @@ fn access_request_multiple_codes() { .get_mut("code") .unwrap() .push("AnotherAuthToken".to_string()); - // Trying to get an access token with mutiple codes, even if one is correct + // Trying to get an access token with multiple codes, even if one is correct let multiple_codes = CraftedRequest { query: None, urlbody: Some(urlbody), @@ -646,7 +641,7 @@ fn unwanted_private_in_body_fails() { auth: None, }; - // in body must only succeed if we enabled it explicitely in the flow. + // in body must only succeed if we enabled it explicitly in the flow. setup.test_simple_error(valid_public); } diff --git a/oxide-auth-async/src/tests/authorization.rs b/oxide-auth-async/src/tests/authorization.rs index 64e7210f..c1199ad4 100644 --- a/oxide-auth-async/src/tests/authorization.rs +++ b/oxide-auth-async/src/tests/authorization.rs @@ -44,6 +44,9 @@ impl<'a> Endpoint for AuthorizationEndpoint<'a> { fn issuer_mut(&mut self) -> Option<&mut (dyn crate::primitives::Issuer + Send)> { None } + fn owner_solicitor(&mut self) -> Option<&mut (dyn OwnerSolicitor + Send)> { + Some(self.solicitor) + } fn scopes(&mut self) -> Option<&mut dyn oxide_auth::endpoint::Scopes> { None } @@ -58,9 +61,6 @@ impl<'a> Endpoint for AuthorizationEndpoint<'a> { fn web_error(&mut self, err: ::Error) -> Self::Error { Error::Web(err) } - fn owner_solicitor(&mut self) -> Option<&mut (dyn OwnerSolicitor + Send)> { - Some(self.solicitor) - } } struct AuthorizationSetup { @@ -89,7 +89,7 @@ impl AuthorizationSetup { fn test_success(&mut self, request: CraftedRequest) { let mut solicitor = Allow(EXAMPLE_OWNER_ID.to_string()); let mut authorization_flow = AuthorizationFlow::prepare(AuthorizationEndpoint::new( - &mut self.registrar, + &self.registrar, &mut self.authorizer, &mut solicitor, )) @@ -99,7 +99,7 @@ impl AuthorizationSetup { assert_eq!(response.status, Status::Redirect); match response.location { - Some(ref url) if url.as_str().find("error").is_none() => (), + Some(ref url) if !url.as_str().contains("error") => (), other => panic!("Expected successful redirect: {:?}", other), } } @@ -107,7 +107,7 @@ impl AuthorizationSetup { fn test_silent_error(&mut self, request: CraftedRequest) { let mut solicitor = Allow(EXAMPLE_OWNER_ID.to_string()); let mut authorization_flow = AuthorizationFlow::prepare(AuthorizationEndpoint::new( - &mut self.registrar, + &self.registrar, &mut self.authorizer, &mut solicitor, )) @@ -124,7 +124,7 @@ impl AuthorizationSetup { P: OwnerSolicitor, { let mut authorization_flow = AuthorizationFlow::prepare(AuthorizationEndpoint::new( - &mut self.registrar, + &self.registrar, &mut self.authorizer, &mut pagehandler, )) @@ -142,10 +142,7 @@ impl AuthorizationSetup { .query_pairs() .collect::>() .get("error") - .is_some() => - { - () - } + .is_some() => {} other => panic!("Expected location with error set description: {:?}", other), } } diff --git a/oxide-auth-async/src/tests/mod.rs b/oxide-auth-async/src/tests/mod.rs index 0c1c564c..66049070 100644 --- a/oxide-auth-async/src/tests/mod.rs +++ b/oxide-auth-async/src/tests/mod.rs @@ -77,8 +77,8 @@ enum CraftedError { } impl WebRequest for CraftedRequest { - type Response = CraftedResponse; type Error = CraftedError; + type Response = CraftedResponse; fn query(&mut self) -> Result, Self::Error> { self.query @@ -139,7 +139,7 @@ impl WebResponse for CraftedResponse { Ok(()) } - /// Json repsonse data, with media type `aplication/json. + /// Json response data, with media type `application/json. fn body_json(&mut self, data: &str) -> Result<(), Self::Error> { self.body = Some(Body::Json(data.to_owned())); Ok(()) diff --git a/oxide-auth-async/src/tests/refresh.rs b/oxide-auth-async/src/tests/refresh.rs index 2a0cbd0d..0629101b 100644 --- a/oxide-auth-async/src/tests/refresh.rs +++ b/oxide-auth-async/src/tests/refresh.rs @@ -2,7 +2,7 @@ use oxide_auth::primitives::issuer::{IssuedToken, RefreshedToken, TokenMap, Toke use oxide_auth::primitives::generator::RandomGenerator; use oxide_auth::primitives::grant::{Grant, Extensions}; use oxide_auth::{ - code_grant::accesstoken::TokenResponse, + code_grant::access_token::TokenResponse, endpoint::{WebRequest}, primitives::registrar::{Client, ClientMap, RegisteredUrl}, frontends::simple::endpoint::Error, @@ -15,9 +15,7 @@ use crate::{ use std::collections::HashMap; -use base64; use chrono::{Utc, Duration}; -use serde_json; use super::{Body, CraftedRequest, CraftedResponse, Status, ToSingleValueQuery}; use super::{defaults::*, resource::ResourceEndpoint}; @@ -42,9 +40,17 @@ impl<'a> Endpoint for RefreshTokenEndpoint<'a> { fn authorizer_mut(&mut self) -> Option<&mut (dyn crate::primitives::Authorizer + Send)> { None } - fn issuer_mut(&mut self) -> Option<&mut (dyn crate::primitives::Issuer + Send)> { + fn issuer_mut(&mut self) -> Option<&mut (dyn Issuer + Send)> { Some(self.issuer) } + fn owner_solicitor( + &mut self, + ) -> Option<&mut (dyn crate::endpoint::OwnerSolicitor + Send)> { + None + } + fn scopes(&mut self) -> Option<&mut dyn oxide_auth::endpoint::Scopes> { + None + } fn response( &mut self, _: &mut CraftedRequest, _: oxide_auth::endpoint::Template, ) -> Result<::Response, Self::Error> { @@ -56,14 +62,6 @@ impl<'a> Endpoint for RefreshTokenEndpoint<'a> { fn web_error(&mut self, _err: ::Error) -> Self::Error { unimplemented!() } - fn scopes(&mut self) -> Option<&mut dyn oxide_auth::endpoint::Scopes> { - None - } - fn owner_solicitor( - &mut self, - ) -> Option<&mut (dyn crate::endpoint::OwnerSolicitor + Send)> { - None - } } struct RefreshTokenSetup { @@ -139,7 +137,7 @@ impl RefreshTokenSetup { assert!(issued.refreshable()); let refresh_token = issued.refresh.clone().unwrap(); - let basic_authorization = "DO_NOT_USE".into(); + let basic_authorization = "DO_NOT_USE".to_string(); RefreshTokenSetup { registrar, @@ -153,7 +151,7 @@ impl RefreshTokenSetup { fn assert_success(&mut self, request: CraftedRequest) -> RefreshedToken { let mut refresh_flow = RefreshFlow::prepare(RefreshTokenEndpoint::new(&self.registrar, &mut self.issuer)).unwrap(); - let response = smol::run(refresh_flow.execute(request)).expect("Expected non-failed reponse"); + let response = smol::run(refresh_flow.execute(request)).expect("Expected non-failed response"); assert_eq!(response.status, Status::Ok); let body = match response.body { Some(Body::Json(body)) => body, @@ -173,7 +171,7 @@ impl RefreshTokenSetup { fn assert_unauthenticated(&mut self, request: CraftedRequest) { let mut refresh_flow = RefreshFlow::prepare(RefreshTokenEndpoint::new(&self.registrar, &mut self.issuer)).unwrap(); - let response = smol::run(refresh_flow.execute(request)).expect("Expected non-failed reponse"); + let response = smol::run(refresh_flow.execute(request)).expect("Expected non-failed response"); let body = self.assert_json_body(&response); if response.status == Status::Unauthorized { assert!(response.www_authenticate.is_some()); @@ -187,7 +185,7 @@ impl RefreshTokenSetup { fn assert_invalid(&mut self, request: CraftedRequest) { let mut refresh_flow = RefreshFlow::prepare(RefreshTokenEndpoint::new(&self.registrar, &mut self.issuer)).unwrap(); - let response = smol::run(refresh_flow.execute(request)).expect("Expected non-failed reponse"); + let response = smol::run(refresh_flow.execute(request)).expect("Expected non-failed response"); let body = self.assert_json_body(&response); assert_eq!(response.status, Status::BadRequest); @@ -211,7 +209,7 @@ impl RefreshTokenSetup { fn assert_wrong_authentication(&mut self, request: CraftedRequest) { let mut refresh_flow = RefreshFlow::prepare(RefreshTokenEndpoint::new(&self.registrar, &mut self.issuer)).unwrap(); - let response = smol::run(refresh_flow.execute(request)).expect("Expected non-failed reponse"); + let response = smol::run(refresh_flow.execute(request)).expect("Expected non-failed response"); assert_eq!(response.status, Status::Unauthorized); assert!(response.www_authenticate.is_some()); @@ -297,7 +295,7 @@ fn access_valid_private() { fn public_private_invalid_grant() { let mut setup = RefreshTokenSetup::public_client(); let client = Client::confidential( - "PrivateClient".into(), + "PrivateClient", RegisteredUrl::Semantic(EXAMPLE_REDIRECT_URI.parse().unwrap()), EXAMPLE_SCOPE.parse().unwrap(), EXAMPLE_PASSPHRASE.as_bytes(), diff --git a/oxide-auth-async/src/tests/resource.rs b/oxide-auth-async/src/tests/resource.rs index 6ab47395..63be45b8 100644 --- a/oxide-auth-async/src/tests/resource.rs +++ b/oxide-auth-async/src/tests/resource.rs @@ -26,6 +26,14 @@ impl<'a> Endpoint for ResourceEndpoint<'a> { fn issuer_mut(&mut self) -> Option<&mut (dyn crate::primitives::Issuer + Send)> { Some(self.issuer) } + fn owner_solicitor( + &mut self, + ) -> Option<&mut (dyn crate::endpoint::OwnerSolicitor + Send)> { + None + } + fn scopes(&mut self) -> Option<&mut dyn oxide_auth::endpoint::Scopes> { + Some(&mut self.scopes) + } fn response( &mut self, _: &mut CraftedRequest, _: oxide_auth::endpoint::Template, ) -> Result<::Response, Self::Error> { @@ -37,14 +45,6 @@ impl<'a> Endpoint for ResourceEndpoint<'a> { fn web_error(&mut self, _err: ::Error) -> Self::Error { unimplemented!() } - fn scopes(&mut self) -> Option<&mut dyn oxide_auth::endpoint::Scopes> { - Some(&mut self.scopes) - } - fn owner_solicitor( - &mut self, - ) -> Option<&mut (dyn crate::endpoint::OwnerSolicitor + Send)> { - None - } } impl<'a> ResourceEndpoint<'a> { @@ -121,9 +121,8 @@ impl ResourceSetup { let mut resource_flow = ResourceFlow::prepare(ResourceEndpoint::new(&mut self.issuer, &mut self.resource_scope)) .unwrap(); - match smol::run(resource_flow.execute(request)) { - Ok(resp) => panic!("Expected an error instead of {:?}", resp), - Err(_) => (), + if let Ok(resp) = smol::run(resource_flow.execute(request)) { + panic!("Expected an error instead of {:?}", resp) } } } diff --git a/oxide-auth-axum/Cargo.toml b/oxide-auth-axum/Cargo.toml index d919c9cd..8b23f7bb 100644 --- a/oxide-auth-axum/Cargo.toml +++ b/oxide-auth-axum/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "oxide-auth-axum" -version = "0.2.0" +version = "0.4.0" authors = ["Daniel Alvsåker "] repository = "https://github.com/HeroicKatora/oxide-auth.git" @@ -13,4 +13,4 @@ edition = "2021" [dependencies] axum = "0.5" -oxide-auth = { version = "0.5", path = "../oxide-auth" } +oxide-auth = { version = "0.6", path = "../oxide-auth" } diff --git a/oxide-auth-axum/src/error.rs b/oxide-auth-axum/src/error.rs index 204a1fb6..a436ca86 100644 --- a/oxide-auth-axum/src/error.rs +++ b/oxide-auth-axum/src/error.rs @@ -8,10 +8,10 @@ use oxide_auth::frontends::{dev::OAuthError, simple::endpoint::Error}; #[derive(Debug)] /// The error type for Oxide Auth operations pub enum WebError { - /// Errors occuring in Endpoint operations + /// Errors occurring in Endpoint operations Endpoint(OAuthError), - /// Errors occuring in Endpoint operations + /// Errors occurring in Endpoint operations Header(InvalidHeaderValue), /// Errors with the request encoding @@ -43,8 +43,10 @@ impl std::fmt::Display for WebError { WebError::Query => write!(f, "No query present"), WebError::Body => write!(f, "No body present"), WebError::Authorization => write!(f, "Request has invalid Authorization headers"), - WebError::InternalError(None) => write!(f, "An internal server error occured"), - WebError::InternalError(Some(ref e)) => write!(f, "An internal server error occured: {}", e), + WebError::InternalError(None) => write!(f, "An internal server error occurred"), + WebError::InternalError(Some(ref e)) => { + write!(f, "An internal server error occurred: {}", e) + } } } } diff --git a/oxide-auth-axum/src/response.rs b/oxide-auth-axum/src/response.rs index 8a5b422d..33e386d6 100644 --- a/oxide-auth-axum/src/response.rs +++ b/oxide-auth-axum/src/response.rs @@ -9,7 +9,7 @@ use axum::{ use oxide_auth::frontends::dev::{WebResponse, Url}; #[derive(Default, Clone, Debug)] -/// Type implementing `WebResponse` and `IntoResponse` for use in route handlers +/// Type implementing [`WebResponse`] and [`IntoResponse`] for use in route handlers pub struct OAuthResponse { status: StatusCode, headers: HeaderMap, @@ -17,7 +17,7 @@ pub struct OAuthResponse { } impl OAuthResponse { - /// Set the `ContentType` header on a response + /// Set the [`ContentType`] header on a response pub fn content_type(mut self, content_type: &str) -> Result { self.headers .insert(header::CONTENT_TYPE, content_type.try_into()?); diff --git a/oxide-auth-db/Cargo.toml b/oxide-auth-db/Cargo.toml index 8c519eb9..328b3b2a 100644 --- a/oxide-auth-db/Cargo.toml +++ b/oxide-auth-db/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "oxide-auth-db" -version = "0.1.0" +version = "0.2.0" authors = ["liujing "] repository = "https://github.com/HeroicKatora/oxide-auth.git" description = "An implement of DB registrar with configurable databases." @@ -10,7 +10,7 @@ license = "MIT OR Apache-2.0" edition = "2018" [dependencies] -oxide-auth = { version = "0.5.1", path = "../oxide-auth" } +oxide-auth = { version = "0.6", path = "../oxide-auth" } once_cell = "1.3.1" rand = "0.7.3" serde = "1.0" diff --git a/oxide-auth-db/examples/db-example/Cargo.toml b/oxide-auth-db/examples/db-example/Cargo.toml index d817755d..939bff84 100644 --- a/oxide-auth-db/examples/db-example/Cargo.toml +++ b/oxide-auth-db/examples/db-example/Cargo.toml @@ -7,9 +7,9 @@ license = "MIT OR Apache-2.0" publish = false [dependencies] -oxide-auth = { version = "0.5.1", path = "../../../oxide-auth" } -oxide-auth-actix = { version = "0.2.0", path = "./../../../oxide-auth-actix" } -oxide-auth-db = { version = "0.1.0", path = "./../../"} +oxide-auth = { version = "0.6", path = "./../../../oxide-auth" } +oxide-auth-actix = { version = "0.3.0", path = "./../../../oxide-auth-actix" } +oxide-auth-db = { version = "0.2.0", path = "./../../../oxide-auth-db"} actix = "0.12" actix-web = "4.0.1" env_logger = "0.7" @@ -21,4 +21,3 @@ serde_urlencoded = "^0.7" url = "2" anyhow = "1.0" r2d2_redis = {version = "0.13"} - diff --git a/oxide-auth-db/examples/db-example/src/main.rs b/oxide-auth-db/examples/db-example/src/main.rs index 85149f07..564786a2 100644 --- a/oxide-auth-db/examples/db-example/src/main.rs +++ b/oxide-auth-db/examples/db-example/src/main.rs @@ -25,15 +25,17 @@ here to begin the authorization process. "; +type GenericEndpoint = Generic< + DBRegistrar, + AuthMap, + TokenMap, + Vacant, + Vec, + fn() -> OAuthResponse, +>; + struct State { - endpoint: Generic< - DBRegistrar, - AuthMap, - TokenMap, - Vacant, - Vec, - fn() -> OAuthResponse, - >, + endpoint: GenericEndpoint, } enum Extras { @@ -43,7 +45,7 @@ enum Extras { } async fn get_authorize( - (req, state): (OAuthRequest, web::Data>), + (req, state): (OAuthRequest, Data>), ) -> Result { // GET requests should not mutate server state and are extremely // vulnerable accidental repetition as well as Cross-Site Request @@ -52,7 +54,7 @@ async fn get_authorize( } async fn post_authorize( - (r, req, state): (HttpRequest, OAuthRequest, web::Data>), + (r, req, state): (HttpRequest, OAuthRequest, Data>), ) -> Result { // Some authentication should be performed here in production cases state @@ -60,19 +62,15 @@ async fn post_authorize( .await? } -async fn token((req, state): (OAuthRequest, web::Data>)) -> Result { +async fn token((req, state): (OAuthRequest, Data>)) -> Result { state.send(Token(req).wrap(Extras::Nothing)).await? } -async fn refresh( - (req, state): (OAuthRequest, web::Data>), -) -> Result { +async fn refresh((req, state): (OAuthRequest, Data>)) -> Result { state.send(Refresh(req).wrap(Extras::Nothing)).await? } -async fn index( - (req, state): (OAuthResource, web::Data>), -) -> Result { +async fn index((req, state): (OAuthResource, Data>)) -> Result { match state .send(Resource(req.into_request()).wrap(Extras::Nothing)) .await? @@ -85,27 +83,27 @@ async fn index( } } -async fn start_browser() -> () { +async fn start_browser() { let _ = thread::spawn(support::open_in_browser); } /// Example of a main function of an actix-web server supporting oauth. #[actix_web::main] pub async fn main() -> std::io::Result<()> { - std::env::set_var( + env::set_var( "RUST_LOG", "actix_example=info,actix_web=info,actix_http=info,actix_service=info", ); - std::env::set_var("REDIS_URL", "redis://localhost/3"); - std::env::set_var("MAX_POOL_SIZE", "32"); + env::set_var("REDIS_URL", "redis://localhost/3"); + env::set_var("MAX_POOL_SIZE", "32"); - std::env::set_var("CLIENT_PREFIX", "client:"); + env::set_var("CLIENT_PREFIX", "client:"); env_logger::init(); let redis_url = env::var("REDIS_URL").expect("REDIS_URL should be set"); - let max_pool_size = env::var("MAX_POOL_SIZE").unwrap_or("32".parse().unwrap()); - let client_prefix = env::var("CLIENT_PREFIX").unwrap_or("client:".parse().unwrap()); + let max_pool_size = env::var("MAX_POOL_SIZE").unwrap_or_else(|_| "32".parse().unwrap()); + let client_prefix = env::var("CLIENT_PREFIX").unwrap_or_else(|_| "client:".parse().unwrap()); // Start, then open in browser, don't care about this finishing. rt::spawn(start_browser()); @@ -167,9 +165,9 @@ impl State { } } - pub fn with_solicitor<'a, S>( - &'a mut self, solicitor: S, - ) -> impl Endpoint + 'a + pub fn with_solicitor( + &'_ mut self, solicitor: S, + ) -> impl Endpoint + '_ where S: OwnerSolicitor + 'static, { @@ -206,7 +204,7 @@ where OAuthResponse::ok() .content_type("text/html") .unwrap() - .body(&crate::support::consent_page_html("/authorize".into(), pre_grant)), + .body(&support::consent_page_html("/authorize", pre_grant)), ) }); diff --git a/oxide-auth-db/src/db_service/redis.rs b/oxide-auth-db/src/db_service/redis.rs index 8bdfeddd..52944e71 100644 --- a/oxide-auth-db/src/db_service/redis.rs +++ b/oxide-auth-db/src/db_service/redis.rs @@ -95,8 +95,8 @@ impl StringfiedEncodedClient { impl RedisDataSource { pub fn new(url: String, max_pool_size: u32, client_prefix: String) -> Result { - let manager = r2d2_redis::RedisConnectionManager::new(url.as_str())?; - let pool = r2d2::Pool::builder().max_size(max_pool_size).build(manager); + let manager = RedisConnectionManager::new(url.as_str())?; + let pool = Pool::builder().max_size(max_pool_size).build(manager); match pool { Ok(pool) => Ok(RedisDataSource { url, @@ -148,7 +148,7 @@ impl OauthClientDBRepository for RedisDataSource { let mut r = self.pool.get()?; let client_str = r.get::<&str, String>(&(self.client_prefix.to_owned() + id))?; let stringfied_client = serde_json::from_str::(&client_str)?; - Ok(stringfied_client.to_encoded_client()?) + stringfied_client.to_encoded_client() } fn regist_from_encoded_client(&self, client: EncodedClient) -> anyhow::Result<()> { diff --git a/oxide-auth-db/src/lib.rs b/oxide-auth-db/src/lib.rs index 0d7f1c70..6829eb3b 100644 --- a/oxide-auth-db/src/lib.rs +++ b/oxide-auth-db/src/lib.rs @@ -8,9 +8,6 @@ pub mod primitives; fn requires_redis_and_should_skip() -> bool { match std::env::var("OXIDE_AUTH_SKIP_REDIS") { Err(_) => false, - Ok(st) => match st.as_str() { - "1" | "yes" => true, - _ => false, - }, + Ok(st) => matches!(st.as_str(), "1" | "yes"), } } diff --git a/oxide-auth-db/src/primitives/db_registrar.rs b/oxide-auth-db/src/primitives/db_registrar.rs index e8f56dd9..c0db6aa4 100644 --- a/oxide-auth-db/src/primitives/db_registrar.rs +++ b/oxide-auth-db/src/primitives/db_registrar.rs @@ -10,14 +10,14 @@ use crate::db_service::DataSource; use r2d2_redis::redis::RedisError; /// A database client service which implemented Registrar. -/// db: repository service to query stored clients or regist new client. +/// db: repository service to query stored clients or register new client. /// password_policy: to encode client_secret. pub struct DBRegistrar { pub repo: DataSource, password_policy: Option>, } -/// methods to search and regist clients from DataSource. +/// methods to search and register clients from DataSource. /// which should be implemented for all DataSource type. pub trait OauthClientDBRepository { fn list(&self) -> anyhow::Result>; @@ -31,7 +31,7 @@ pub trait OauthClientDBRepository { // Implementations of DB Registrars // /////////////////////////////////////////////////////////////////////////////////////////////////// -static DEFAULT_PASSWORD_POLICY: Lazy = Lazy::new(|| Argon2::default()); +static DEFAULT_PASSWORD_POLICY: Lazy = Lazy::new(Argon2::default); impl DBRegistrar { /// Create an DB connection recording to features. @@ -59,7 +59,7 @@ impl DBRegistrar { } // This is not an instance method because it needs to borrow the box but register needs &mut - fn current_policy<'a>(policy: &'a Option>) -> &'a dyn PasswordPolicy { + fn current_policy(policy: &Option>) -> &dyn PasswordPolicy { policy .as_ref() .map(|boxed| &**boxed) @@ -73,7 +73,7 @@ impl Extend for DBRegistrar { I: IntoIterator, { iter.into_iter().for_each(|client| { - self.register_client(client); + let _err = self.register_client(client); // swallow errors }) } } @@ -86,7 +86,7 @@ impl Registrar for DBRegistrar { }; // Perform exact matching as motivated in the rfc let registered_url = match bound.redirect_uri { - None => client.redirect_uri.clone(), + None => client.redirect_uri, Some(ref url) => { let original = std::iter::once(&client.redirect_uri); let alternatives = client.additional_redirect_uris.iter(); @@ -106,9 +106,7 @@ impl Registrar for DBRegistrar { }) } - fn negotiate<'a>( - &self, bound: BoundClient<'a>, _scope: Option, - ) -> Result { + fn negotiate(&self, bound: BoundClient, _scope: Option) -> Result { let client = self .repo .find_client_by_id(&bound.client_id) @@ -196,7 +194,7 @@ mod tests { "client:".parse().unwrap(), ) .unwrap(); - db_registrar.register_client(client); + let _err = db_registrar.register_client(client); assert_eq!( db_registrar @@ -256,14 +254,13 @@ mod tests { "default".parse().unwrap(), ); - oauth_service.register_client(public_client); + let _err = oauth_service.register_client(public_client); oauth_service .check(public_id, None) .expect("Authorization of public client has changed"); oauth_service .check(public_id, Some(b"")) - .err() - .expect("Authorization with password succeeded"); + .expect_err("Authorization with password succeeded"); let private_client = Client::confidential( private_id, @@ -272,14 +269,13 @@ mod tests { private_passphrase, ); - oauth_service.register_client(private_client); + let _err = oauth_service.register_client(private_client); oauth_service .check(private_id, Some(private_passphrase)) .expect("Authorization with right password did not succeed"); oauth_service .check(private_id, Some(b"Not the private passphrase")) - .err() - .expect("Authorization succeed with wrong password"); + .expect_err("Authorization succeed with wrong password"); } } diff --git a/oxide-auth-iron/Cargo.toml b/oxide-auth-iron/Cargo.toml index fd3af5a9..a2ee6ad3 100644 --- a/oxide-auth-iron/Cargo.toml +++ b/oxide-auth-iron/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "oxide-auth-iron" -version = "0.1.0" +version = "0.3.0" authors = ["Andreas Molzer "] repository = "https://github.com/HeroicKatora/oxide-auth.git" @@ -13,7 +13,7 @@ edition = "2018" [dependencies] iron = "0.6" -oxide-auth = { version = "0.5.0", path = "../oxide-auth" } +oxide-auth = { version = "0.6", path = "../oxide-auth" } serde_urlencoded = "0.7" url = "2" diff --git a/oxide-auth-iron/examples/iron.rs b/oxide-auth-iron/examples/iron.rs index e44603fd..31e6cdbf 100644 --- a/oxide-auth-iron/examples/iron.rs +++ b/oxide-auth-iron/examples/iron.rs @@ -6,7 +6,7 @@ extern crate router; use std::sync::{Arc, Mutex}; use std::thread::spawn; -use iron::{Iron, Request, Response}; +use iron::{Iron, IronError, Request, Response}; use iron::headers::ContentType; use iron::status::Status; use iron::middleware::Handler; @@ -15,6 +15,7 @@ use oxide_auth::endpoint::{OwnerConsent, Solicitation}; use oxide_auth::frontends::simple::endpoint::{FnSolicitor, Generic, Vacant}; use oxide_auth::primitives::prelude::*; use oxide_auth_iron::{OAuthRequest, OAuthResponse, OAuthError}; +use oxide_auth::frontends::simple::endpoint::Error as FError; #[rustfmt::skip] #[path = "../../examples/support/iron.rs"] @@ -31,7 +32,7 @@ fn main_router() -> impl Handler + 'static { // One clone for each of the move-closures below. let (auth_get_state, auth_post_state, token_state, get_state) = - (state.clone(), state.clone(), state.clone(), state.clone()); + (state.clone(), state.clone(), state.clone(), state); let mut router = router::Router::new(); router.get( "/authorize", @@ -42,9 +43,10 @@ fn main_router() -> impl Handler + 'static { .with_solicitor(FnSolicitor(consent_form)) .authorization_flow() .execute(request.into()) - .map_err(|e| { - let e: OAuthError = e.into(); - e.into() + .map_err(|e: FError| { + let e = OAuthError::from(e); + let err: IronError = e.into(); + err })?; Ok(response.into()) }, @@ -59,9 +61,10 @@ fn main_router() -> impl Handler + 'static { .with_solicitor(FnSolicitor(consent_decision)) .authorization_flow() .execute(request.into()) - .map_err(|e| { - let e: OAuthError = e.into(); - e.into() + .map_err(|e: FError| { + let e = OAuthError::from(e); + let err: IronError = e.into(); + err })?; Ok(response.into()) }, @@ -75,9 +78,10 @@ fn main_router() -> impl Handler + 'static { .endpoint() .access_token_flow() .execute(request.into()) - .map_err(|e| { - let e: OAuthError = e.into(); - e.into() + .map_err(|e: FError| { + let e = OAuthError::from(e); + let err: IronError = e.into(); + err })?; Ok(response.into()) }, @@ -162,7 +166,7 @@ here to begin the authorization process. } } - /// In larger app, you'd likey wrap it in your own Endpoint instead of `Generic`. + /// In larger app, you'd likely wrap it in your own Endpoint instead of `Generic`. pub fn endpoint( &self, ) -> Generic< diff --git a/oxide-auth-iron/src/lib.rs b/oxide-auth-iron/src/lib.rs index 131e626e..5c82d083 100644 --- a/oxide-auth-iron/src/lib.rs +++ b/oxide-auth-iron/src/lib.rs @@ -7,7 +7,7 @@ use std::borrow::Cow; use oxide_auth::endpoint::{OAuthError as EndpointError, QueryParameter, WebRequest, WebResponse}; -use oxide_auth::frontends::simple::endpoint::Error as SimpleError; +use oxide_auth::frontends::simple::endpoint::Error as FError; use iron::{Request, Response}; use iron::error::IronError; @@ -80,7 +80,7 @@ impl OAuthResponse { OAuthResponse(Response::new()) } - /// Createa a new OAuthResponse from an existing `iron::Response` + /// Create a new OAuthResponse from an existing `iron::Response` pub fn from_response(response: Response) -> Self { OAuthResponse(response) } @@ -109,10 +109,16 @@ impl OAuthResponse { } } +impl Default for OAuthResponse { + fn default() -> Self { + Self::new() + } +} + /// Requests are handed as mutable reference to the underlying object. impl<'a, 'b, 'c: 'b> WebRequest for OAuthRequest<'a, 'b, 'c> { - type Response = OAuthResponse; type Error = Error; + type Response = OAuthResponse; fn query(&mut self) -> Result, Self::Error> { serde_urlencoded::from_str(self.query_string()) @@ -181,9 +187,9 @@ impl<'a, 'b, 'c: 'b> From<&'a mut Request<'b, 'c>> for OAuthRequest<'a, 'b, 'c> } } -impl<'a, 'b, 'c: 'b> Into<&'a mut Request<'b, 'c>> for OAuthRequest<'a, 'b, 'c> { - fn into(self) -> &'a mut Request<'b, 'c> { - self.0 +impl<'a, 'b, 'c: 'b> From> for &'a mut Request<'b, 'c> { + fn from(oauth_req: OAuthRequest<'a, 'b, 'c>) -> Self { + oauth_req.0 } } @@ -193,17 +199,18 @@ impl From for OAuthResponse { } } -impl Into for OAuthResponse { - fn into(self) -> Response { - self.0 +impl From for Response { + fn from(oauth_resp: OAuthResponse) -> Self { + oauth_resp.0 } } -impl<'a, 'b, 'c: 'b> From>> for OAuthError { - fn from(error: SimpleError>) -> Self { +impl<'a, 'b, 'c: 'b> From>> for OAuthError { + fn from(error: FError>) -> Self { let as_oauth = match error { - SimpleError::Web(Error::BadRequest) => EndpointError::BadRequest, - SimpleError::OAuth(oauth) => oauth, + // if you see an IDE error here its not you or this code, its your IDE. + FError::Web(_) => EndpointError::BadRequest, + FError::OAuth(oauth) => oauth, }; let status = match as_oauth { @@ -222,8 +229,8 @@ impl From for OAuthError { } } -impl Into for OAuthError { - fn into(self) -> IronError { - self.0 +impl From for IronError { + fn from(oauth_err: OAuthError) -> Self { + oauth_err.0 } } diff --git a/oxide-auth-poem/Cargo.toml b/oxide-auth-poem/Cargo.toml index 89a33eb3..587a340c 100644 --- a/oxide-auth-poem/Cargo.toml +++ b/oxide-auth-poem/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "oxide-auth-poem" -version = "0.1.0" +version = "0.2.0" repository = "https://github.com/HeroicKatora/oxide-auth.git" authors = ["l1npengtul "] description = "A OAuth2 server library for Poem featuring a set of configurable and pluggable backends." @@ -14,6 +14,6 @@ edition = "2021" [dependencies] poem = "1.3" -oxide-auth = { version = "0.5", path = "../oxide-auth" } +oxide-auth = { version = "0.6", path = "../oxide-auth" } thiserror = "1.0" serde_urlencoded = "0.7" diff --git a/oxide-auth-rocket/Cargo.toml b/oxide-auth-rocket/Cargo.toml index f7bc855d..41027a21 100644 --- a/oxide-auth-rocket/Cargo.toml +++ b/oxide-auth-rocket/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "oxide-auth-rocket" -version = "0.1.0" +version = "0.2.0" authors = ["Andreas Molzer "] repository = "https://github.com/HeroicKatora/oxide-auth.git" @@ -15,7 +15,7 @@ edition = "2018" [dependencies] rocket = "0.4.2" -oxide-auth = { version = "0.5.0", path = "../oxide-auth" } +oxide-auth = { version = "0.6", path = "../oxide-auth" } serde_urlencoded = "0.7" [dev-dependencies] diff --git a/oxide-auth-rocket/examples/rocket.rs b/oxide-auth-rocket/examples/rocket.rs index 7ecb8588..19dc57d1 100644 --- a/oxide-auth-rocket/examples/rocket.rs +++ b/oxide-auth-rocket/examples/rocket.rs @@ -166,7 +166,7 @@ fn consent_form<'r>( OwnerConsent::InProgress( Response::build() .status(http::Status::Ok) - .header(http::ContentType::HTML) + .header(ContentType::HTML) .sized_body(io::Cursor::new(support::consent_page_html( "/authorize", solicitation, diff --git a/oxide-auth-rocket/src/lib.rs b/oxide-auth-rocket/src/lib.rs index 96c4bcf7..92a0cdcd 100644 --- a/oxide-auth-rocket/src/lib.rs +++ b/oxide-auth-rocket/src/lib.rs @@ -31,7 +31,7 @@ pub struct OAuthRequest<'r> { /// Response type for Rocket OAuth requests /// /// A simple wrapper type around a simple `rocket::Response<'r>` that implements `WebResponse`. -#[derive(Debug)] +#[derive(Debug, Default)] pub struct OAuthResponse<'r>(Response<'r>); /// Request error at the http layer. @@ -74,7 +74,7 @@ impl<'r> OAuthRequest<'r> { let optional = all_auth.next(); // Duplicate auth header, just treat it as no authorization. - let auth = if let Some(_) = all_auth.next() { + let auth = if all_auth.next().is_some() { None } else { optional.map(str::to_owned) @@ -97,7 +97,7 @@ impl<'r> OAuthRequest<'r> { pub fn add_body(&mut self, data: Data) { // Nothing to do if we already have a body, or already generated an error. This includes // the case where the content type does not indicate a form, as the error is silent until a - // body is explicitely requested. + // body is explicitly requested. if let Ok(None) = self.body { match serde_urlencoded::from_reader(data.open()) { Ok(query) => self.body = Ok(Some(query)), @@ -139,7 +139,7 @@ impl<'r> WebRequest for OAuthRequest<'r> { } fn authheader(&mut self) -> Result>, Self::Error> { - Ok(self.auth.as_ref().map(String::as_str).map(Cow::Borrowed)) + Ok(self.auth.as_deref().map(Cow::Borrowed)) } } @@ -205,20 +205,14 @@ impl<'r> Responder<'r> for WebError { } } -impl<'r> Default for OAuthResponse<'r> { - fn default() -> Self { - OAuthResponse(Default::default()) - } -} - impl<'r> From> for OAuthResponse<'r> { fn from(r: Response<'r>) -> Self { OAuthResponse::from_response(r) } } -impl<'r> Into> for OAuthResponse<'r> { - fn into(self) -> Response<'r> { - self.0 +impl<'r> From> for Response<'r> { + fn from(oauth_resp: OAuthResponse<'r>) -> Self { + oauth_resp.0 } } diff --git a/oxide-auth-rouille/Cargo.toml b/oxide-auth-rouille/Cargo.toml index 7faf76e9..e17dab94 100644 --- a/oxide-auth-rouille/Cargo.toml +++ b/oxide-auth-rouille/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "oxide-auth-rouille" -version = "0.1.0" +version = "0.2.0" authors = ["Andreas Molzer "] repository = "https://github.com/HeroicKatora/oxide-auth.git" edition = "2018" @@ -13,7 +13,7 @@ license = "MIT OR Apache-2.0" [dependencies] rouille = "3.0" -oxide-auth = { version = "0.5.0", path = "../oxide-auth" } +oxide-auth = { version = "0.6", path = "../oxide-auth" } serde_urlencoded = "0.7" url = "2" diff --git a/oxide-auth-rouille/examples/rouille.rs b/oxide-auth-rouille/examples/rouille.rs index ea02df48..db3bbc84 100644 --- a/oxide-auth-rouille/examples/rouille.rs +++ b/oxide-auth-rouille/examples/rouille.rs @@ -136,12 +136,12 @@ here to begin the authorization process. /// the flow. fn solicitor(request: &mut Request, grant: Solicitation<'_>) -> OwnerConsent { if request.method() == "GET" { - let text = support::consent_page_html("/authorize".into(), grant); + let text = support::consent_page_html("/authorize", grant); let response = Response::html(text); OwnerConsent::InProgress(response.into()) } else if request.method() == "POST" { // No real user authentication is done here, in production you MUST use session keys or equivalent - if let Some(_) = request.get_param("allow") { + if request.get_param("allow").is_some() { OwnerConsent::Authorized("dummy user".to_string()) } else { OwnerConsent::Denied diff --git a/oxide-auth-rouille/src/lib.rs b/oxide-auth-rouille/src/lib.rs index 613c24a8..02c371f2 100644 --- a/oxide-auth-rouille/src/lib.rs +++ b/oxide-auth-rouille/src/lib.rs @@ -6,10 +6,7 @@ use core::ops::Deref; use std::borrow::Cow; - use oxide_auth::endpoint::{QueryParameter, WebRequest, WebResponse}; - -use rouille; use url::Url; // In the spirit of simplicity, this module does not implement any wrapper structures. In order to diff --git a/oxide-auth/Cargo.toml b/oxide-auth/Cargo.toml index 03432854..d9c5d7b8 100644 --- a/oxide-auth/Cargo.toml +++ b/oxide-auth/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "oxide-auth" -version = "0.5.1" +version = "0.6.0" authors = ["Andreas Molzer "] repository = "https://github.com/HeroicKatora/oxide-auth.git" edition = "2018" diff --git a/oxide-auth/Changes.md b/oxide-auth/Changes.md index 712d7386..44d708e4 100644 --- a/oxide-auth/Changes.md +++ b/oxide-auth/Changes.md @@ -83,7 +83,7 @@ Added token refresh Allow client secret in access token request body - Optional, and NOT RECOMMENDED feature of rfc6749. -- Can be explicitely enabled in an `AccessTokenFlow`. +- Can be explicitly enabled in an `AccessTokenFlow`. Ergonomic improvements - Reworked examples to be based on the same client. Thus, they all have similar @@ -205,7 +205,7 @@ Renamings (`old` -> `new`): Thanks and More: For all of you that stick with me during the long period of seeming inactivity, this has been an exciting year. I've grown a lot in Rust and as a - developer. The first versions were coined by a bit of naivity on my part and + developer. The first versions were coined by a bit of naivety on my part and this one hopefully feels more mature and idiomatic. # v0.3.1 (2018-Mar-30) @@ -259,7 +259,7 @@ Introduced the following features: A trait based system allows passing a collection of extensions to request handlers. After the basic request checks passed, extensions can handle additional parameters of the request. Based on - inidivudual logic, they can block the request with an error, attach + individual logic, they can block the request with an error, attach additional information or simply pass it on. Any attached information become available to the same extension in subsequent requests with the employed grant. diff --git a/oxide-auth/src/code_grant/accesstoken.rs b/oxide-auth/src/code_grant/access_token.rs similarity index 97% rename from oxide-auth/src/code_grant/accesstoken.rs rename to oxide-auth/src/code_grant/access_token.rs index bb06642f..97c456c3 100644 --- a/oxide-auth/src/code_grant/accesstoken.rs +++ b/oxide-auth/src/code_grant/access_token.rs @@ -73,7 +73,7 @@ pub trait Request { /// RECOMMENDED and need not be supported. The parameters MUST NOT appear in the request URI /// itself. /// - /// Under these considerations, support must be explicitely enabled. + /// Under these considerations, support must be explicitly enabled. fn allow_credentials_in_body(&self) -> bool { false } @@ -143,7 +143,7 @@ enum Credentials<'a> { /// parameters for the first step will be extracted from it. It will pose some requests in the form /// of [`Output`] which should be satisfied with the next [`Input`] data. This will eventually /// produce a [`BearerToken`] or an [`Error`]. Note that the executing environment will need to use -/// a [`Registrar`], an [`Authorizer`], an optionnal [`Extension`] and an [`Issuer`] to which some +/// a [`Registrar`], an [`Authorizer`], an optional [`Extension`] and an [`Issuer`] to which some /// requests should be forwarded. /// /// [`Input`]: struct.Input.html @@ -237,14 +237,14 @@ pub enum Output<'machine> { }, /// The extension (if any) should provide the extensions /// - /// Fullfilled by `Input::Extended` + /// Fulfilled by `Input::Extended` Extend { /// The grant extensions if any extensions: &'machine mut Extensions, }, /// The issue should issue a new access token /// - /// Fullfilled by `Input::Issued` + /// Fulfilled by `Input::Issued` Issue { /// The grant to be used in the token generation grant: &'machine Grant, @@ -280,7 +280,7 @@ impl AccessToken { .. }, Input::Authenticated, - ) => Self::authencicated(client, code, redirect_uri), + ) => Self::authenticated(client, code, redirect_uri), ( AccessTokenState::Recover { client, redirect_uri, .. @@ -368,7 +368,7 @@ impl AccessToken { }) } - fn authencicated(client: String, code: String, redirect_uri: url::Url) -> AccessTokenState { + fn authenticated(client: String, code: String, redirect_uri: url::Url) -> AccessTokenState { AccessTokenState::Recover { client, code, @@ -384,7 +384,9 @@ impl AccessToken { Some(v) => v, }; - if (saved_params.client_id.as_str(), &saved_params.redirect_uri) != (&client_id, &redirect_uri) { + if (saved_params.client_id.as_str(), &saved_params.redirect_uri) + != (client_id.as_str(), &redirect_uri) + { return Err(Error::invalid_with(AccessTokenErrorType::InvalidGrant)); } @@ -534,16 +536,16 @@ pub enum Error { } /// The endpoint should have enough control over its primitives to find -/// out what has gone wrong, e.g. they may externall supply error +/// out what has gone wrong, e.g. they may external supply error /// information. /// /// In this case, all previous results returned by the primitives are /// included in the return value. Through this mechanism, one can -/// accomodate async handlers by implementing a sync-based result cache +/// accommodate async handlers by implementing a sync-based result cache /// that is filled with these partial values. In case only parts of the /// outstanding futures, invoked during internal calls, are ready the /// cache can be refilled through the error eliminating polls to already -/// sucessful futures. +/// successful futures. /// /// Note that `token` is not included in this list, since the handler /// can never fail after supplying a token to the backend. @@ -559,7 +561,7 @@ pub struct PrimitiveError { pub extensions: Option, } -/// Simple wrapper around AccessTokenError to imbue the type with addtional json functionality. In +/// Simple wrapper around AccessTokenError to imbue the type with additional json functionality. In /// addition this enforces backend specific behaviour for obtaining or handling the access error. #[derive(Clone)] pub struct ErrorDescription { diff --git a/oxide-auth/src/code_grant/authorization.rs b/oxide-auth/src/code_grant/authorization.rs index 0d598046..9e63de78 100644 --- a/oxide-auth/src/code_grant/authorization.rs +++ b/oxide-auth/src/code_grant/authorization.rs @@ -1,15 +1,17 @@ //! Provides the handling for Authorization Code Requests use std::borrow::Cow; use std::result::Result as StdResult; - use url::Url; use chrono::{Duration, Utc}; - -use crate::code_grant::error::{AuthorizationError, AuthorizationErrorType}; -use crate::primitives::authorizer::Authorizer; -use crate::primitives::registrar::{ClientUrl, ExactUrl, Registrar, RegistrarError, PreGrant}; -use crate::primitives::grant::{Extensions, Grant}; -use crate::{endpoint::Scope, endpoint::Solicitation, primitives::registrar::BoundClient}; +use crate::{ + code_grant::error::{AuthorizationError, AuthorizationErrorType}, + primitives::{ + authorizer::Authorizer, + registrar::{ClientUrl, ExactUrl, Registrar, RegistrarError, PreGrant, BoundClient}, + grant::{Extensions, Grant}, + }, + endpoint::{Scope, Solicitation}, +}; /// Interface required from a request to determine the handling in the backend. pub trait Request { @@ -70,7 +72,7 @@ pub trait Endpoint { fn extension(&mut self) -> &mut dyn Extension; } -/// The result will indicate wether the authorization succeed or not. +/// The result will indicate whether the authorization succeed or not. pub struct Authorization { state: AuthorizationState, extensions: Option, @@ -136,7 +138,7 @@ pub enum Output<'machine> { }, /// Ask for extensions if any Extend, - /// Ask registrar to negociate + /// Ask registrar to negotiate Negotiate { /// The current bound client bound_client: &'machine BoundClient<'static>, @@ -170,7 +172,7 @@ impl Authorization { } /// Go to next state - pub fn advance<'req>(&mut self, input: Input<'req>) -> Output<'_> { + pub fn advance(&mut self, input: Input) -> Output { self.state = match (self.take(), input) { (current, Input::None) => current, ( @@ -207,7 +209,7 @@ impl Authorization { }, AuthorizationState::Extending { .. } => Output::Extend, AuthorizationState::Negotiating { bound_client } => Output::Negotiate { - bound_client: &bound_client, + bound_client, scope: self.scope.clone(), }, AuthorizationState::Pending { @@ -216,7 +218,7 @@ impl Authorization { extensions, } => Output::Ok { pre_grant: pre_grant.clone(), - state: state.clone(), + state: state.as_ref().map(Clone::clone), extensions: extensions.clone(), }, } @@ -302,14 +304,14 @@ impl Authorization { /// Retrieve allowed scope and redirect url from the registrar. /// -/// Checks the validity of any given input as the registrar instance communicates the registrated +/// Checks the validity of any given input as the registrar instance communicates the registered /// parameters. The registrar can also set or override the requested (default) scope of the client. /// This will result in a tuple of negotiated parameters which can be used further to authorize /// the client by the owner or, in case of errors, in an action to be taken. /// If the client is not registered, the request will otherwise be ignored, if the request has /// some other syntactical error, the client is contacted at its redirect url with an error /// response. -pub fn authorization_code(handler: &mut dyn Endpoint, request: &dyn Request) -> self::Result { +pub fn authorization_code(handler: &mut dyn Endpoint, request: &dyn Request) -> Result { enum Requested { None, Bind { @@ -425,9 +427,9 @@ pub fn authorization_code(handler: &mut dyn Endpoint, request: &dyn Request) -> } /// Represents a valid, currently pending authorization request not bound to an owner. The frontend -/// can signal a reponse using this object. +/// can signal a response using this object. // Don't ever implement `Clone` here. It's to make it very -// hard for the user toaccidentally respond to a request in two conflicting ways. This has +// hard for the user to accidentally respond to a request in two conflicting ways. This has // potential security impact if it could be both denied and authorized. pub struct Pending { pre_grant: PreGrant, @@ -506,7 +508,7 @@ pub enum Error { /// Encapsulates a redirect to a valid redirect_uri with an error response. The implementation /// makes it possible to alter the contained error, for example to provide additional optional -/// information. The error type should not be altered by the frontend but the specificalities +/// information. The error type should not be altered by the frontend but the specifics /// of this should be enforced by the frontend instead. #[derive(Clone)] pub struct ErrorUrl { @@ -565,11 +567,10 @@ impl Error { } } -impl Into for ErrorUrl { - /// Finalize the error url by saving its parameters in the query part of the redirect_uri - fn into(self) -> Url { - let mut url = self.base_uri; - url.query_pairs_mut().extend_pairs(self.error.into_iter()); +impl From for Url { + fn from(err_url: ErrorUrl) -> Self { + let mut url = err_url.base_uri; + url.query_pairs_mut().extend_pairs(err_url.error.into_iter()); url } } diff --git a/oxide-auth/src/code_grant/extensions/pkce.rs b/oxide-auth/src/code_grant/extensions/pkce.rs index 9b68b9bf..a598427d 100644 --- a/oxide-auth/src/code_grant/extensions/pkce.rs +++ b/oxide-auth/src/code_grant/extensions/pkce.rs @@ -152,12 +152,17 @@ impl Method { } fn from_encoded(encoded: Cow) -> Result { - // TODO: avoid allocation in case of borrow and invalid. - let mut encoded = encoded.into_owned(); - match encoded.pop() { - None => Err(()), - Some('p') => Ok(Method::Plain(encoded)), - Some('S') => Ok(Method::Sha256(encoded)), + match encoded.chars().last() { + Some('p') => { + let mut string = encoded.into_owned(); + string.pop(); + Ok(Method::Plain(string)) + } + Some('S') => { + let mut string = encoded.into_owned(); + string.pop(); + Ok(Method::Sha256(string)) + } _ => Err(()), } } diff --git a/oxide-auth/src/code_grant/mod.rs b/oxide-auth/src/code_grant/mod.rs index 673de597..1dfbd306 100644 --- a/oxide-auth/src/code_grant/mod.rs +++ b/oxide-auth/src/code_grant/mod.rs @@ -3,9 +3,9 @@ //! The backend codifies the requirements for the from the [RFC 6749] into types and functions as //! safely as possible. The result of the backend are abstract results, actions which should be //! executed or relayed by the frontend using its available types. Abstract in this sense means -//! that the reponses from the backend are not generic on an input type. +//! that the responses from the backend are not generic on an input type. //! -//! Another consideration is the possiblilty of reusing some components with other oauth schemes. +//! Another consideration is the possibility of reusing some components with other oauth schemes. //! In this way, the backend is used to group necessary types and as an interface to implementors, //! to be able to infer the range of applicable end effectors (i.e. authorizers, issuer, //! registrars). @@ -27,7 +27,7 @@ //! [`endpoint`]: ../endpoint/index.html //! [`Endpoint`]: ../endpoint/trait.Endpoint.html -pub mod accesstoken; +pub mod access_token; pub mod authorization; pub mod error; pub mod extensions; diff --git a/oxide-auth/src/code_grant/refresh.rs b/oxide-auth/src/code_grant/refresh.rs index 5e02a84b..97ce2d83 100644 --- a/oxide-auth/src/code_grant/refresh.rs +++ b/oxide-auth/src/code_grant/refresh.rs @@ -5,7 +5,7 @@ use std::collections::HashMap; use chrono::{Duration, Utc}; use crate::code_grant::{ - accesstoken::TokenResponse, + access_token::TokenResponse, error::{AccessTokenError, AccessTokenErrorType}, }; use crate::primitives::grant::Grant; @@ -237,7 +237,7 @@ impl Refresh { /// /// The provided `Input` needs to fulfill the *previous* `Output` request. See their /// documentation for more information. - pub fn advance<'req>(&mut self, input: Input<'req>) -> Output<'_> { + pub fn advance(&mut self, input: Input) -> Output { // Breaking change for 0.6 // Run the next state transition if we got the right input. Errors that happen will be // stored as a inescapable error state. match (self.take(), input) { @@ -301,7 +301,7 @@ impl Refresh { client: &grant.client_id, pass: None, }, - RefreshState::Recovering { token, .. } => Output::RecoverRefresh { token: &token }, + RefreshState::Recovering { token, .. } => Output::RecoverRefresh { token }, RefreshState::Issuing { token, grant, .. } => Output::Refresh { token, grant: grant.clone(), @@ -478,7 +478,7 @@ fn validate(scope: Option>, grant: Box, token: String) -> Result let scope = match scope { Some(scope) => { // ... MUST NOT include any scope not originally granted. - if !grant.scope.priviledged_to(&scope) { + if !grant.scope.privileged_to(&scope) { // ... or exceeds the scope grant (Section 5.2) return Err(Error::invalid(AccessTokenErrorType::InvalidScope)); } diff --git a/oxide-auth/src/code_grant/resource.rs b/oxide-auth/src/code_grant/resource.rs index 5691bd88..f49faeb6 100644 --- a/oxide-auth/src/code_grant/resource.rs +++ b/oxide-auth/src/code_grant/resource.rs @@ -26,7 +26,7 @@ pub enum ErrorCode { /// The request did not have enough authorization data or was otherwise malformed. InvalidRequest, - /// The provided authorization did not grant sufficient priviledges. + /// The provided authorization did not grant sufficient privileges. InsufficientScope, /// The token is expired, revoked, malformed or otherwise does not meet expectations. @@ -122,6 +122,7 @@ enum ResourceState { /// An input injected by the executor into the state machine. #[derive(Clone)] +#[allow(clippy::large_enum_variant)] pub enum Input<'req> { /// Provide the queried (bearer) token. Recovered(Option), @@ -215,6 +216,12 @@ impl Resource { } } +impl Default for Resource { + fn default() -> Self { + Self::new() + } +} + /// Do needed verification before granting access to the resource pub fn protect(handler: &mut dyn Endpoint, req: &dyn Request) -> Result { enum Requested { diff --git a/oxide-auth/src/endpoint/accesstoken.rs b/oxide-auth/src/endpoint/access_token.rs similarity index 91% rename from oxide-auth/src/endpoint/accesstoken.rs rename to oxide-auth/src/endpoint/access_token.rs index 02ab88a0..2a3da04e 100644 --- a/oxide-auth/src/endpoint/accesstoken.rs +++ b/oxide-auth/src/endpoint/access_token.rs @@ -1,11 +1,17 @@ use std::str::from_utf8; use std::marker::PhantomData; -use crate::code_grant::accesstoken::{ - access_token, Error as TokenError, Extension, Endpoint as TokenEndpoint, Request as TokenRequest, +use crate::{ + code_grant::access_token::{ + access_token, Error as TokenError, Extension, Endpoint as TokenEndpoint, Request as TokenRequest, + }, + endpoint::NormalizedParameter, }; -use super::*; +use super::{ + Authorizer, Cow, Endpoint, InnerTemplate, Issuer, OAuthError, QueryParameter, Registrar, WebRequest, + WebResponse, +}; /// Offers access tokens to authenticated third parties. /// @@ -16,7 +22,7 @@ use super::*; /// /// Client credentials can be allowed to appear in the request body instead of being /// required to be passed as HTTP Basic authorization. This is not recommended and must be -/// enabled explicitely. See [`allow_credentials_in_body`] for details. +/// enabled explicitly. See [`allow_credentials_in_body`] for details. /// /// [`allow_credentials_in_body`]: #method.allow_credentials_in_body pub struct AccessTokenFlow @@ -70,7 +76,15 @@ where /// Binds the endpoint to a particular type of request that it supports, for many /// implementations this is probably single type anyways. /// - /// ## Panics + /// # Errors + /// The endpoint needs to give a `Some(_)` value for + /// - `registrar` + /// - `authorizer` + /// - `issuer` + /// + /// otherwise this will error. + /// + /// # Panics /// /// Indirectly `execute` may panic when this flow is instantiated with an inconsistent /// endpoint, for details see the documentation of `Endpoint` and `execute`. For @@ -104,15 +118,18 @@ where /// RECOMMENDED and need not be supported. The parameters MUST NOT appear in the request URI /// itself. /// - /// Thus support is disabled by default and must be explicitely enabled. + /// Thus support is disabled by default and must be explicitly enabled. pub fn allow_credentials_in_body(&mut self, allow: bool) { self.allow_credentials_in_body = allow; } /// Use the checked endpoint to check for authorization for a resource. /// - /// ## Panics + /// # Errors + /// If the token returned by the request and handler is invalid, or setting the response body as JSON fails this + /// will error. /// + /// # Panics /// When the registrar, authorizer, or issuer returned by the endpoint is suddenly /// `None` when previously it was `Some(_)`. pub fn execute(&mut self, mut request: R) -> Result { @@ -225,7 +242,7 @@ impl<'a, R: WebRequest + 'a> WrappedRequest<'a, R> { fn from_err(err: FailParse) -> Self { WrappedRequest { request: PhantomData, - body: Cow::Owned(Default::default()), + body: Cow::Owned(NormalizedParameter::default()), authorization: None, error: Some(err), allow_credentials_in_body: false, diff --git a/oxide-auth/src/endpoint/authorization.rs b/oxide-auth/src/endpoint/authorization.rs index 6eae17d6..e091bd8d 100644 --- a/oxide-auth/src/endpoint/authorization.rs +++ b/oxide-auth/src/endpoint/authorization.rs @@ -1,9 +1,15 @@ -use crate::code_grant::authorization::{ - authorization_code, Error as AuthorizationError, Extension, Endpoint as AuthorizationEndpoint, - Request as AuthorizationRequest, Pending, +use crate::{ + code_grant::authorization::{ + authorization_code, Error as AuthorizationError, Extension, Endpoint as AuthorizationEndpoint, + Request as AuthorizationRequest, Pending, + }, + endpoint::NormalizedParameter }; -use super::*; +use super::{ + Authorizer, Cow, Endpoint, InnerTemplate, OAuthError, OwnerConsent, OwnerSolicitor, PhantomData, + QueryParameter, Registrar, Url, WebRequest, WebResponse, +}; /// All relevant methods for handling authorization code requests. pub struct AuthorizationFlow @@ -97,8 +103,10 @@ where /// Binds the endpoint to a particular type of request that it supports, for many /// implementations this is probably single type anyways. /// - /// ## Panics + /// # Errors + /// /// + /// # Panics /// Indirectly `execute` may panic when this flow is instantiated with an inconsistent /// endpoint, for details see the documentation of `Endpoint`. For consistent endpoints, /// the panic is instead caught as an error here. @@ -124,9 +132,11 @@ where /// /// In almost all cases this is followed by executing `finish` on the result but some users may /// instead want to inspect the partial result. - /// - /// ## Panics - /// + /// + /// # Errors + /// If the authorization code negotiation fails, the authorization flow fails to complete this will error + /// + /// # Panics /// When the registrar or the authorizer returned by the endpoint is suddenly `None` when /// previously it was `Some(_)`. pub fn execute(&mut self, mut request: R) -> Result { @@ -291,7 +301,7 @@ impl<'a, R: WebRequest + 'a> WrappedRequest<'a, R> { fn from_err(err: R::Error) -> Self { WrappedRequest { request: PhantomData, - query: Cow::Owned(Default::default()), + query: Cow::Owned(NormalizedParameter::default()), error: Some(err), } } diff --git a/oxide-auth/src/endpoint/mod.rs b/oxide-auth/src/endpoint/mod.rs index ff3c35c5..3b25c656 100644 --- a/oxide-auth/src/endpoint/mod.rs +++ b/oxide-auth/src/endpoint/mod.rs @@ -29,7 +29,7 @@ //! [`Issuer`]: ../../primitives/issuer/trait.Issuer.html //! [`Registrar`]: ../../primitives/registrar/trait.Registrar.html mod authorization; -mod accesstoken; +mod access_token; mod error; mod refresh; mod resource; @@ -53,17 +53,17 @@ use url::Url; // Re-export the extension traits under prefixed names. pub use crate::code_grant::authorization::Extension as AuthorizationExtension; -pub use crate::code_grant::accesstoken::Extension as AccessTokenExtension; +pub use crate::code_grant::access_token::Extension as AccessTokenExtension; pub use crate::primitives::registrar::PreGrant; pub use self::authorization::*; -pub use self::accesstoken::*; +pub use self::access_token::*; pub use self::error::OAuthError; pub use self::refresh::RefreshFlow; pub use self::resource::*; pub use self::query::*; -/// Answer from OwnerAuthorizer to indicate the owners choice. +/// Answer from `OwnerAuthorizer` to indicate the owners choice. pub enum OwnerConsent { /// The owner did not authorize the client. Denied, @@ -124,6 +124,7 @@ enum InnerTemplate<'a> { /// The underlying cause for denying access. /// /// The http authorization header is to be set according to this field. + #[allow(dead_code)] error: Option, /// Information on an access token error. @@ -146,7 +147,7 @@ enum InnerTemplate<'a> { authorization_error: Option<&'a mut AuthorizationError>, }, - /// The request did not conform to specification or was otheriwse invalid. + /// The request did not conform to specification or was otherwise invalid. /// /// As such, it was not handled further. Some processes still warrant a response body to be /// set in the case of an invalid request, containing additional information for the client. @@ -183,6 +184,7 @@ impl<'flow> Solicitation<'flow> { /// Clone the solicitation into an owned structure. /// /// This mainly helps with sending it across threads. + #[must_use] pub fn into_owned(self) -> Solicitation<'static> { Solicitation { grant: Cow::Owned(self.grant.into_owned()), @@ -195,6 +197,7 @@ impl<'flow> Solicitation<'flow> { /// The information in the `PreGrant` is the authoritative information on the client and scopes /// associated with the request. It has already been validated against those settings and /// restrictions that were applied when registering the client. + #[must_use] pub fn pre_grant(&self) -> &PreGrant { self.grant.as_ref() } @@ -203,17 +206,16 @@ impl<'flow> Solicitation<'flow> { /// /// This will need to be provided to the response back to the client so it must be preserved /// across a redirect or a consent screen presented by the user agent. + #[must_use] pub fn state(&self) -> Option<&str> { - match self.state { - None => None, - Some(ref state) => Some(&state), - } + self.state.as_ref().map(AsRef::as_ref) } /// Create a new solicitation request from a pre grant. /// /// You usually wouldn't need to call this manually as it is called by the endpoint's flow and /// then handed with all available information to the solicitor. + #[must_use] pub fn new(grant: &'flow PreGrant) -> Self { Solicitation { grant: Cow::Borrowed(grant), @@ -222,6 +224,7 @@ impl<'flow> Solicitation<'flow> { } /// Add a client state to the solicitation. + #[must_use] pub fn with_state(self, state: &'flow str) -> Self { Solicitation { state: Some(Cow::Borrowed(state)), @@ -296,24 +299,31 @@ pub trait WebRequest { /// Retrieve a parsed version of the url query. /// - /// An Err return value indicates a malformed query or an otherwise malformed WebRequest. Note + /// # Errors + /// An Err return value indicates a malformed query or an otherwise malformed [`WebRequest`]. Note /// that an empty query should result in `Ok(HashMap::new())` instead of an Err. fn query(&mut self) -> Result, Self::Error>; /// Retrieve the parsed `application/x-form-urlencoded` body of the request. /// + /// # Errors /// An Err value / indicates a malformed body or a different Content-Type. fn urlbody(&mut self) -> Result, Self::Error>; - /// Contents of the authorization header or none if none exists. An Err value indicates a - /// malformed header or request. + /// Contents of the authorization header or none if none exists. + /// + /// # Errors + /// An Err value indicates a malformed header or request. fn authheader(&mut self) -> Result>, Self::Error>; } -/// Response representation into which the Request is transformed by the code_grant types. +/// Response representation into which the Request is transformed by the `code_grant` types. /// /// At most one of the methods `body_text`, `body_json` will be called. Some flows will /// however not call any of those methods. +/// # Errors +/// If one of these fields failed to set, the method will error +#[allow(clippy::missing_errors_doc)] pub trait WebResponse { /// The error generated when trying to construct an unhandled or invalid response. type Error; @@ -333,7 +343,7 @@ pub trait WebResponse { /// A pure text response with no special media type set. fn body_text(&mut self, text: &str) -> Result<(), Self::Error>; - /// Json repsonse data, with media type `aplication/json. + /// Json response data, with media type `application/json`. fn body_json(&mut self, data: &str) -> Result<(), Self::Error>; } @@ -526,7 +536,7 @@ impl<'a> Template<'a> { /// Slightly tweaked from an `Into`, there is `Option<&'a mut T>` from `&'a mut Option`. fn reborrow<'a, T>(opt: &'a mut Option<&mut T>) -> Option<&'a mut T> { match opt { - // Magically does correct lifetime coercision. + // Magically does correct lifetime coercion. Some(inner) => Some(inner), None => None, } diff --git a/oxide-auth/src/endpoint/query.rs b/oxide-auth/src/endpoint/query.rs index 56db07c4..432bc90f 100644 --- a/oxide-auth/src/endpoint/query.rs +++ b/oxide-auth/src/endpoint/query.rs @@ -18,6 +18,7 @@ use serde::Deserializer; /// * `HashMap>` /// * `HashMap, Cow<'static, str>>` /// +/// # Safety /// You should generally not have to implement this trait yourself, and if you do there are /// additional requirements on your implementation to guarantee standard conformance. Therefore the /// trait is marked as `unsafe`. @@ -41,7 +42,7 @@ pub unsafe trait QueryParameter { /// in the memory associated with the request, it needs to be allocated to outlive the borrow on /// the request. This allocation may as well perform the minimization/normalization into a /// representation actually consumed by the backend. This normal form thus encapsulates the -/// associated `clone-into-normal form` by various possible constructors from references [WIP]. +/// associated `clone-into-normal form` by various possible constructors from references \[WIP\]. /// /// This gives rise to a custom `Cow` instance by requiring that normalization into /// memory with unrelated lifetime is always possible. @@ -67,6 +68,7 @@ unsafe impl QueryParameter for NormalizedParameter { impl NormalizedParameter { /// Create an empty map. + #[must_use] pub fn new() -> Self { NormalizedParameter::default() } @@ -115,7 +117,7 @@ impl<'de> de::Deserialize<'de> for NormalizedParameter { A: de::SeqAccess<'a>, { while let Some((key, value)) = access.next_element::<(String, String)>()? { - self.0.insert_or_poison(key.into(), value.into()) + self.0.insert_or_poison(key.into(), value.into()); } Ok(self.0) @@ -166,6 +168,10 @@ impl ToOwned for dyn QueryParameter + Send { /// /// If this were done with slices, that would require choosing a particular /// value type of the underlying slice e.g. `[String]`. +/// +/// # Safety +/// Generally, you do not need to implement this yourself. However, there are constraints for +/// correct implementations if you do, thus this trait is marked `unsafe`. pub unsafe trait UniqueValue { /// Borrow the unique value reference. fn get_unique(&self) -> Option<&str>; @@ -259,7 +265,7 @@ unsafe impl UniqueValue for str { unsafe impl UniqueValue for String { fn get_unique(&self) -> Option<&str> { - Some(&self) + Some(self) } } @@ -325,7 +331,7 @@ unsafe impl UniqueValue for Vec { mod test { use super::*; - /// Compilation tests for various possible QueryParameter impls. + /// Compilation tests for various possible [`QueryParameter`] impls. #[allow(unused)] #[allow(dead_code)] fn test_query_parameter_impls() { diff --git a/oxide-auth/src/endpoint/refresh.rs b/oxide-auth/src/endpoint/refresh.rs index 6a589e14..6187dd60 100644 --- a/oxide-auth/src/endpoint/refresh.rs +++ b/oxide-auth/src/endpoint/refresh.rs @@ -2,8 +2,11 @@ use std::borrow::Cow; use std::marker::PhantomData; use std::str::from_utf8; -use crate::code_grant::refresh::{refresh, Error, Endpoint as RefreshEndpoint, Request}; -use crate::primitives::{registrar::Registrar, issuer::Issuer}; +use crate::{ + code_grant::refresh::{refresh, Error, Endpoint as RefreshEndpoint, Request}, + endpoint::NormalizedParameter, + primitives::{registrar::Registrar, issuer::Issuer} +}; use super::{Endpoint, InnerTemplate, OAuthError, QueryParameter, WebRequest, WebResponse}; /// Takes requests from clients to refresh their access tokens. @@ -48,14 +51,16 @@ where { /// Wrap the endpoint if it supports handling refresh requests. /// - /// Also binds the endpoint to the particular `WebRequest` type through the type system. The - /// endpoint needs to provide (return `Some`): + /// Also binds the endpoint to the particular [`WebRequest`] type through the type system. /// + /// # Errors + /// The endpoint needs to provide (return `Some`): /// * a `Registrar` from `registrar` /// * an `Issuer` from `issuer_mut` /// - /// ## Panics + /// otherwise the method will error. /// + /// # Panics /// Indirectly `execute` may panic when this flow is instantiated with an inconsistent /// endpoint, for details see the documentation of `Endpoint` and `execute`. For /// consistent endpoints, the panic is instead caught as an error here. @@ -78,8 +83,11 @@ where /// Use the checked endpoint to refresh a token. /// - /// ## Panics + /// # Errors + /// If the token returned by the request and handler is invalid, or setting the response body as JSON fails this + /// will error. /// + /// # Panics /// When the registrar, authorizer, or issuer returned by the endpoint is suddenly /// `None` when previously it was `Some(_)`. pub fn execute(&mut self, mut request: R) -> Result { @@ -167,13 +175,14 @@ impl<'a, R: WebRequest + 'a> WrappedRequest<'a, R> { fn from_err(err: InitError) -> Self { WrappedRequest { request: PhantomData, - body: Cow::Owned(Default::default()), + body: Cow::Owned(NormalizedParameter::default()), authorization: None, error: Some(err), } } - fn parse_header(header: Cow) -> Result> { + fn parse_header(header: impl AsRef) -> Result> { + let header = header.as_ref(); let authorization = { if !header.starts_with("Basic ") { return Err(InitError::Malformed); @@ -225,12 +234,6 @@ impl<'a, R: WebRequest> Request for WrappedRequest<'a, R> { self.body.unique_value("refresh_token") } - fn authorization(&self) -> Option<(Cow, Cow<[u8]>)> { - self.authorization - .as_ref() - .map(|auth| (auth.0.as_str().into(), auth.1.as_slice().into())) - } - fn scope(&self) -> Option> { self.body.unique_value("scope") } @@ -239,6 +242,12 @@ impl<'a, R: WebRequest> Request for WrappedRequest<'a, R> { self.body.unique_value("grant_type") } + fn authorization(&self) -> Option<(Cow, Cow<[u8]>)> { + self.authorization + .as_ref() + .map(|auth| (auth.0.as_str().into(), auth.1.as_slice().into())) + } + fn extension(&self, key: &str) -> Option> { self.body.unique_value(key) } diff --git a/oxide-auth/src/endpoint/resource.rs b/oxide-auth/src/endpoint/resource.rs index b3e49d0a..e537ef8e 100644 --- a/oxide-auth/src/endpoint/resource.rs +++ b/oxide-auth/src/endpoint/resource.rs @@ -5,7 +5,7 @@ use crate::code_grant::resource::{ }; use crate::primitives::grant::Grant; -use super::*; +use super::{Endpoint, InnerTemplate, Issuer, OAuthError, PhantomData, Scope, WebRequest, WebResponse}; /// Guards resources by requiring OAuth authorization. pub struct ResourceFlow @@ -46,8 +46,13 @@ where /// Binds the endpoint to a particular type of request that it supports, for many /// implementations this is probably single type anyways. /// - /// ## Panics + /// # Errors + /// The endpoint must return `Some(_)` for + /// - `issuer` + /// - `scopes` + /// otherwise this will error. /// + /// # Panics /// Indirectly `execute` may panic when this flow is instantiated with an inconsistent /// endpoint, for details see the documentation of `Endpoint` and `execute`. For /// consistent endpoints, the panic is instead caught as an error here. @@ -88,14 +93,12 @@ where fn denied(&mut self, request: &mut R, error: ResourceError) -> Result { let template = match &error { - ResourceError::AccessDenied { .. } => InnerTemplate::Unauthorized { - error: None, - access_token_error: None, - }, - ResourceError::NoAuthentication { .. } => InnerTemplate::Unauthorized { - error: None, - access_token_error: None, - }, + ResourceError::NoAuthentication { .. } | ResourceError::AccessDenied { .. } => { + InnerTemplate::Unauthorized { + error: None, + access_token_error: None, + } + } ResourceError::InvalidRequest { .. } => InnerTemplate::BadRequest { access_token_error: None, }, @@ -116,8 +119,11 @@ where impl WrappedRequest { fn new(request: &mut R) -> Self { let token = match request.authheader() { - // TODO: this is unecessarily wasteful, we always clone. - Ok(Some(token)) => Some(token.into_owned()), + // TODO: this is unnecessarily wasteful, we always clone. + Ok(Some(token)) => Some(match token { + Cow::Borrowed(b) => b.to_string(), + Cow::Owned(o) => o, + }), Ok(None) => None, Err(error) => return Self::from_error(error), }; diff --git a/oxide-auth/src/endpoint/tests/access_token.rs b/oxide-auth/src/endpoint/tests/access_token.rs index aa39bb8a..39585f23 100644 --- a/oxide-auth/src/endpoint/tests/access_token.rs +++ b/oxide-auth/src/endpoint/tests/access_token.rs @@ -249,7 +249,7 @@ fn access_equivalent_url() { #[test] fn access_request_unknown_client() { let mut setup = AccessTokenSetup::private_client(); - // Trying to autenticate as some unknown client with the passphrase + // Trying to authenticate as some unknown client with the passphrase let unknown_client = CraftedRequest { query: None, urlbody: Some( @@ -273,7 +273,7 @@ fn access_request_unknown_client() { #[test] fn access_request_wrong_authentication() { let mut setup = AccessTokenSetup::private_client(); - // Trying to autenticate with an unsupported method (instead of Basic) + // Trying to authenticate with an unsupported method (instead of Basic) let wrong_authentication = CraftedRequest { query: None, urlbody: Some( @@ -294,7 +294,7 @@ fn access_request_wrong_authentication() { #[test] fn access_request_wrong_password() { let mut setup = AccessTokenSetup::private_client(); - // Trying to autenticate with the wrong password + // Trying to authenticate with the wrong password let wrong_password = CraftedRequest { query: None, urlbody: Some( @@ -318,7 +318,7 @@ fn access_request_wrong_password() { #[test] fn access_request_empty_password() { let mut setup = AccessTokenSetup::private_client(); - // Trying to autenticate with an empty password + // Trying to authenticate with an empty password let empty_password = CraftedRequest { query: None, urlbody: Some( @@ -339,7 +339,7 @@ fn access_request_empty_password() { #[test] fn access_request_multiple_client_indications() { let mut setup = AccessTokenSetup::private_client(); - // Trying to autenticate with an unsupported method (instead of Basic) + // Trying to authenticate with an unsupported method (instead of Basic) let multiple_client_indications = CraftedRequest { query: None, urlbody: Some( @@ -361,7 +361,7 @@ fn access_request_multiple_client_indications() { #[test] fn access_request_public_authorization() { let mut setup = AccessTokenSetup::public_client(); - // Trying to autenticate a public client + // Trying to authenticate a public client let public_authorization = CraftedRequest { query: None, urlbody: Some( @@ -382,7 +382,7 @@ fn access_request_public_authorization() { #[test] fn access_request_public_missing_client() { let mut setup = AccessTokenSetup::public_client(); - // Trying to autenticate with an unsupported method (instead of Basic) + // Trying to authenticate with an unsupported method (instead of Basic) let public_missing_client = CraftedRequest { query: None, urlbody: Some( @@ -403,7 +403,7 @@ fn access_request_public_missing_client() { #[test] fn access_request_invalid_basic() { let mut setup = AccessTokenSetup::private_client(); - // Trying to autenticate with an invalid basic authentication header + // Trying to authenticate with an invalid basic authentication header let invalid_basic = CraftedRequest { query: None, urlbody: Some( @@ -497,7 +497,7 @@ fn access_request_multiple_codes() { .get_mut("code") .unwrap() .push("AnotherAuthToken".to_string()); - // Trying to get an access token with mutiple codes, even if one is correct + // Trying to get an access token with multiple codes, even if one is correct let multiple_codes = CraftedRequest { query: None, urlbody: Some(urlbody), @@ -571,7 +571,7 @@ fn unwanted_private_in_body_fails() { auth: None, }; - // in body must only succeed if we enabled it explicitely in the flow. + // in body must only succeed if we enabled it explicitly in the flow. setup.test_simple_error(valid_public); } diff --git a/oxide-auth/src/endpoint/tests/authorization.rs b/oxide-auth/src/endpoint/tests/authorization.rs index 116bb39b..bace546c 100644 --- a/oxide-auth/src/endpoint/tests/authorization.rs +++ b/oxide-auth/src/endpoint/tests/authorization.rs @@ -36,7 +36,7 @@ impl AuthorizationSetup { fn test_success(&mut self, request: CraftedRequest) { let response = authorization_flow( - &mut self.registrar, + &self.registrar, &mut self.authorizer, &mut Allow(EXAMPLE_OWNER_ID.to_string()), ) @@ -46,14 +46,14 @@ impl AuthorizationSetup { assert_eq!(response.status, Status::Redirect); match response.location { - Some(ref url) if url.as_str().find("error").is_none() => (), + Some(ref url) if !url.as_str().contains("error") => (), other => panic!("Expected successful redirect: {:?}", other), } } fn test_silent_error(&mut self, request: CraftedRequest) { match authorization_flow( - &mut self.registrar, + &self.registrar, &mut self.authorizer, &mut Allow(EXAMPLE_OWNER_ID.to_string()), ) @@ -69,8 +69,8 @@ impl AuthorizationSetup { where P: OwnerSolicitor, { - let response = authorization_flow(&mut self.registrar, &mut self.authorizer, &mut pagehandler) - .execute(request); + let response = + authorization_flow(&self.registrar, &mut self.authorizer, &mut pagehandler).execute(request); let response = match response { Err(resp) => panic!("Expected redirect with error set: {:?}", resp), @@ -83,10 +83,7 @@ impl AuthorizationSetup { .query_pairs() .collect::>() .get("error") - .is_some() => - { - () - } + .is_some() => {} other => panic!("Expected location with error set description: {:?}", other), } } @@ -166,9 +163,9 @@ fn auth_request_silent_mismatching_redirect() { fn auth_request_silent_mismatching_literal_redirect() { // The redirect_uri does not match if stringly matched. let mut setup = AuthorizationSetup::new(); - const UNIQUE_CLIENT: &'static str = "client_auth_request_silent_mismatching_literal_redirect"; - const REGISTERED_URL: &'static str = "https://right.client.example/endpoint"; - const TRIED_URL: &'static str = "https://right.client.example/endpoint/"; + const UNIQUE_CLIENT: &str = "client_auth_request_silent_mismatching_literal_redirect"; + const REGISTERED_URL: &str = "https://right.client.example/endpoint"; + const TRIED_URL: &str = "https://right.client.example/endpoint/"; let client = Client::confidential( UNIQUE_CLIENT, diff --git a/oxide-auth/src/endpoint/tests/mod.rs b/oxide-auth/src/endpoint/tests/mod.rs index 97cb61e9..50c41eee 100644 --- a/oxide-auth/src/endpoint/tests/mod.rs +++ b/oxide-auth/src/endpoint/tests/mod.rs @@ -74,8 +74,8 @@ enum CraftedError { } impl WebRequest for CraftedRequest { - type Response = CraftedResponse; type Error = CraftedError; + type Response = CraftedResponse; fn query(&mut self) -> Result, Self::Error> { self.query diff --git a/oxide-auth/src/endpoint/tests/pkce.rs b/oxide-auth/src/endpoint/tests/pkce.rs index eeb68159..8b9b72da 100644 --- a/oxide-auth/src/endpoint/tests/pkce.rs +++ b/oxide-auth/src/endpoint/tests/pkce.rs @@ -3,7 +3,7 @@ use crate::primitives::issuer::TokenMap; use crate::primitives::generator::RandomGenerator; use crate::primitives::registrar::{Client, ClientMap, RegisteredUrl}; -use crate::code_grant::accesstoken::TokenResponse; +use crate::code_grant::access_token::TokenResponse; use crate::endpoint::{AuthorizationFlow, AccessTokenFlow, Endpoint}; use crate::frontends::simple::extensions::{AddonList, Extended, Pkce}; use crate::frontends::simple::endpoint::{Generic, Error, Vacant}; @@ -38,9 +38,9 @@ impl PkceSetup { let issuer = TokenMap::new(RandomGenerator::new(16)); PkceSetup { - registrar: registrar, - authorizer: authorizer, - issuer: issuer, + registrar, + authorizer, + issuer, auth_token: token, // The following are from https://tools.ietf.org/html/rfc7636#page-18 sha256_challenge: "E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM".to_string(), @@ -125,13 +125,13 @@ impl PkceSetup { fn assert_nonerror_redirect(response: CraftedResponse) { assert_eq!(response.status, Status::Redirect, "Expected redirect to client"); - assert!(response.location.unwrap().as_str().find("error").is_none()); + assert!(!response.location.unwrap().as_str().contains("error")); } fn json_response(body: Option) -> TokenResponse { let body = match body { Some(Body::Json(content)) => content, - other => panic!("Expected json formated credentials, got {:?}", other), + other => panic!("Expected json formatted credentials, got {:?}", other), }; serde_json::from_str(&body).expect("Body not json encoded") diff --git a/oxide-auth/src/endpoint/tests/refresh.rs b/oxide-auth/src/endpoint/tests/refresh.rs index 8a6f308e..5e4075c6 100644 --- a/oxide-auth/src/endpoint/tests/refresh.rs +++ b/oxide-auth/src/endpoint/tests/refresh.rs @@ -11,7 +11,7 @@ use serde_json; use super::{Body, CraftedRequest, CraftedResponse, Status, ToSingleValueQuery}; use super::defaults::*; -use crate::code_grant::accesstoken::TokenResponse; +use crate::code_grant::access_token::TokenResponse; use crate::frontends::simple::endpoint::{refresh_flow, resource_flow}; struct RefreshTokenSetup { @@ -89,7 +89,7 @@ impl RefreshTokenSetup { assert!(issued.refreshable()); let refresh_token = issued.refresh.clone().unwrap(); - let basic_authorization = "DO_NOT_USE".into(); + let basic_authorization = "DO_NOT_USE".to_string(); RefreshTokenSetup { registrar, @@ -103,7 +103,7 @@ impl RefreshTokenSetup { fn assert_success(&mut self, request: CraftedRequest) -> RefreshedToken { let response = refresh_flow(&self.registrar, &mut self.issuer) .execute(request) - .expect("Expected non-failed reponse"); + .expect("Expected non-failed response"); assert_eq!(response.status, Status::Ok); let body = match response.body { Some(Body::Json(body)) => body, @@ -123,7 +123,7 @@ impl RefreshTokenSetup { fn assert_unauthenticated(&mut self, request: CraftedRequest) { let response = refresh_flow(&self.registrar, &mut self.issuer) .execute(request) - .expect("Expected non-failed reponse"); + .expect("Expected non-failed response"); let body = self.assert_json_body(&response); if response.status == Status::Unauthorized { assert!(response.www_authenticate.is_some()); @@ -137,7 +137,7 @@ impl RefreshTokenSetup { fn assert_invalid(&mut self, request: CraftedRequest) { let response = refresh_flow(&self.registrar, &mut self.issuer) .execute(request) - .expect("Expected non-failed reponse"); + .expect("Expected non-failed response"); let body = self.assert_json_body(&response); assert_eq!(response.status, Status::BadRequest); @@ -149,7 +149,7 @@ impl RefreshTokenSetup { fn assert_invalid_grant(&mut self, request: CraftedRequest) { let response = refresh_flow(&self.registrar, &mut self.issuer) .execute(request) - .expect("Expected non-failed reponse"); + .expect("Expected non-failed response"); let body = self.assert_json_body(&response); assert_eq!(response.status, Status::BadRequest); @@ -161,7 +161,7 @@ impl RefreshTokenSetup { fn assert_wrong_authentication(&mut self, request: CraftedRequest) { let response = refresh_flow(&self.registrar, &mut self.issuer) .execute(request) - .expect("Expected non-failed reponse"); + .expect("Expected non-failed response"); assert_eq!(response.status, Status::Unauthorized); assert!(response.www_authenticate.is_some()); @@ -247,7 +247,7 @@ fn access_valid_private() { fn public_private_invalid_grant() { let mut setup = RefreshTokenSetup::public_client(); let client = Client::confidential( - "PrivateClient".into(), + "PrivateClient", RegisteredUrl::Semantic(EXAMPLE_REDIRECT_URI.parse().unwrap()), EXAMPLE_SCOPE.parse().unwrap(), EXAMPLE_PASSPHRASE.as_bytes(), diff --git a/oxide-auth/src/endpoint/tests/resource.rs b/oxide-auth/src/endpoint/tests/resource.rs index 7de71fdd..e38dc79b 100644 --- a/oxide-auth/src/endpoint/tests/resource.rs +++ b/oxide-auth/src/endpoint/tests/resource.rs @@ -75,9 +75,8 @@ impl ResourceSetup { } fn test_access_error(&mut self, request: CraftedRequest) { - match resource_flow(&mut self.issuer, &self.resource_scope).execute(request) { - Ok(resp) => panic!("Expected an error instead of {:?}", resp), - Err(_) => (), + if let Ok(resp) = resource_flow(&mut self.issuer, &self.resource_scope).execute(request) { + panic!("Expected an error instead of {:?}", resp) } } } diff --git a/oxide-auth/src/frontends/gotham.rs b/oxide-auth/src/frontends/gotham.rs index 2e7d3111..95e4fa9d 100644 --- a/oxide-auth/src/frontends/gotham.rs +++ b/oxide-auth/src/frontends/gotham.rs @@ -79,17 +79,17 @@ use std::sync::{Arc, Mutex, LockResult, MutexGuard}; /// A struct that wraps all oauth related services and makes them available through state. #[derive(StateData, Clone)] pub struct GothamOauthProvider { - registrar: Arc>, - authorizer: Arc>, - issuer: Arc>, + registrar: Arc>, + authorizer: Arc>, + issuer: Arc>, } impl GothamOauthProvider { - /// Constructs a new Gotham OAuth provider, wrapping all the common oauth services. - pub fn new(registrar: R, data: A, issuer: I) -> Self where + pub fn new(registrar: R, data: A, issuer: I) -> Self + where R: Registrar + Send + 'static, A: Authorizer + Send + 'static, - I: Issuer + Send + 'static + I: Issuer + Send + 'static, { Self { registrar: Arc::new(Mutex::new(registrar)), @@ -98,18 +98,18 @@ impl GothamOauthProvider { } } - /// Thread-safely access the underlying registrar, which is responsible for client registrarion. - pub fn registrar(&self) -> LockResult> { + /// Thread-safely access the underlying registrar, which is responsible for client registration. + pub fn registrar(&self) -> LockResult> { self.registrar.lock() } /// Thread-safely access the underlying authorizer, which builds and holds authorization codes. - pub fn authorizer(&self) -> LockResult> { + pub fn authorizer(&self) -> LockResult> { self.authorizer.lock() } /// Thread-safely access the underlying issuer, which builds and holds access tokens. - pub fn issuer(&self) -> LockResult> { + pub fn issuer(&self) -> LockResult> { self.issuer.lock() } @@ -121,10 +121,9 @@ impl GothamOauthProvider { let mut request = Request::new(method.clone(), uri.clone()); for header in headers.iter() { - request.headers_mut().set_raw( - header.name().to_owned(), - header.raw().clone() - ); + request + .headers_mut() + .set_raw(header.name().to_owned(), header.raw().clone()); } request @@ -162,7 +161,7 @@ pub struct OAuthStateDataMiddleware { impl OAuthStateDataMiddleware { /// Construct a new middleware containing the provider that wraps all common auth services. pub fn new(provider: GothamOauthProvider) -> Self { - Self { provider: provider } + Self { provider } } } @@ -186,7 +185,7 @@ pub struct OAuthGuardMiddleware { impl OAuthGuardMiddleware { /// Construct a new guard middleware with the scopes that it should guard against. pub fn new(scopes: Vec) -> Self { - Self { scopes: scopes } + Self { scopes } } } @@ -196,18 +195,16 @@ impl Middleware for OAuthGuardMiddleware { Chain: FnOnce(State) -> Box + 'static, { let oauth = state.borrow::().clone(); - let f = oauth.guard_request(&state).then(move |result| { - match result { - Ok(guard) => { - let mut issuer = oauth.issuer().unwrap(); - let flow = AccessFlow::new(&mut *issuer, self.scopes.as_slice()); - match guard.handle(flow) { - Ok(_) => chain(state), - Err(e) => Box::new(future::err((state, e.into_handler_error()))) - } - }, - Err(e) => Box::new(future::err((state, e.into_handler_error()))), + let f = oauth.guard_request(&state).then(move |result| match result { + Ok(guard) => { + let mut issuer = oauth.issuer().unwrap(); + let flow = AccessFlow::new(&mut *issuer, self.scopes.as_slice()); + match guard.handle(flow) { + Ok(_) => chain(state), + Err(e) => Box::new(future::err((state, e.into_handler_error()))), + } } + Err(e) => Box::new(future::err((state, e.into_handler_error()))), }); Box::new(f) @@ -252,22 +249,26 @@ impl WebRequest for ResolvedRequest { type Response = Response; fn query(&mut self) -> Result { - self.query.as_ref().map(|query| QueryParameter::SingleValue( - SingleValueQuery::StringValue(Cow::Borrowed(query)))) + self.query + .as_ref() + .map(|query| { + QueryParameter::SingleValue(SingleValueQuery::StringValue(Cow::Borrowed(query))) + }) .ok_or(()) } fn urlbody(&mut self) -> Result { - self.body.as_ref().map(|body| QueryParameter::SingleValue( - SingleValueQuery::StringValue(Cow::Borrowed(body)))) + self.body + .as_ref() + .map(|body| QueryParameter::SingleValue(SingleValueQuery::StringValue(Cow::Borrowed(body)))) .ok_or(()) } - fn authheader(&mut self) -> Result>, ()>{ + fn authheader(&mut self) -> Result>, ()> { match &self.authorization { &Ok(Some(ref string)) => Ok(Some(Cow::Borrowed(string))), &Ok(None) => Ok(None), - &Err(_) => Err(()) + &Err(_) => Err(()), } } } @@ -316,10 +317,10 @@ impl WebResponse for Response { /// Add an `WWW-Authenticate` header fn with_authorization(mut self, kind: &str) -> Result { - self.headers_mut().set_raw("WWW-Authenticate", vec![kind.as_bytes().to_vec()]); + self.headers_mut() + .set_raw("WWW-Authenticate", vec![kind.as_bytes().to_vec()]); Ok(self) } - } impl ResolvedRequest { @@ -334,9 +335,9 @@ impl ResolvedRequest { }); ResolvedRequest { - request: request, - authorization: authorization, - query: query, + request, + authorization, + query, body: None, } } @@ -354,9 +355,11 @@ struct ResolvedOwnerAuthorization { impl OwnerAuthorizer for ResolvedOwnerAuthorization where - A: Fn(&Request, &PreGrant) -> OwnerAuthorization + A: Fn(&Request, &PreGrant) -> OwnerAuthorization, { - fn check_authorization(self, request: ResolvedRequest, grant: &PreGrant) -> OwnerAuthorization { + fn check_authorization( + self, request: ResolvedRequest, grant: &PreGrant, + ) -> OwnerAuthorization { // @todo Investigate passing along the state. (self.handler)(&request.request, grant) } @@ -372,26 +375,23 @@ impl Future for AuthorizationCodeRequest { } } - impl Future for GrantRequest { type Item = ReadyGrantRequest; type Error = OAuthError; fn poll(&mut self) -> Poll { match self.body.take().unwrap().poll() { - Ok(Async::Ready(body)) => { - body.and_then(|valid_body| { - String::from_utf8(valid_body.to_vec()).ok() - }) + Ok(Async::Ready(body)) => body + .and_then(|valid_body| String::from_utf8(valid_body.to_vec()).ok()) .and_then(|body_string| { serde_urlencoded::from_str::>(body_string.as_str()).ok() }) .and_then(|decoded_body| { - let resolved = ResolvedRequest::with_body(self.request.take().unwrap(), decoded_body); + let resolved = + ResolvedRequest::with_body(self.request.take().unwrap(), decoded_body); Some(Async::Ready(ReadyGrantRequest(resolved))) }) - .ok_or_else(|| OAuthError::BadRequest) - }, + .ok_or_else(|| OAuthError::BadRequest), Ok(Async::NotReady) => Ok(Async::NotReady), // Not a valid url encoded body @@ -412,11 +412,12 @@ impl Future for GuardRequest { impl ReadyAuthorizationCodeRequest { /// Wrapper proxy method to the handler of authorization flow, passing the resolved request. - pub fn handle(self, flow: AuthorizationFlow, authorizer: A)-> Result + pub fn handle(self, flow: AuthorizationFlow, authorizer: A) -> Result where - A: Fn(&Request, &PreGrant) -> OwnerAuthorization + A: Fn(&Request, &PreGrant) -> OwnerAuthorization, { - flow.handle(self.0).complete(ResolvedOwnerAuthorization { handler: authorizer }) + flow.handle(self.0) + .complete(ResolvedOwnerAuthorization { handler: authorizer }) } } diff --git a/oxide-auth/src/frontends/mod.rs b/oxide-auth/src/frontends/mod.rs index 8c9f7e12..c4a17a39 100644 --- a/oxide-auth/src/frontends/mod.rs +++ b/oxide-auth/src/frontends/mod.rs @@ -18,8 +18,8 @@ //! //! ## Guide to implementing a custom front-end //! -//! All front-end implementations should start with two closely related traits: [`WebRequest`] and -//! [`WebResponse`]. These central interfaces are used to interact with the libraries supported +//! All front-end implementations should start with two closely related traits: `WebRequest` and +//! `WebResponse`. These central interfaces are used to interact with the libraries supported //! token flows (currently only authorization code grant). //! //! Lets step through those implementations one by one. As an example request type, let's pretend @@ -92,19 +92,19 @@ //! # } //! //! impl WebRequest for ExampleRequest { -//! // Declare the corresponding response type. -//! type Response = ExampleResponse; -//! //! // Our internal frontends error type is `OAuthError` //! type Error = OAuthError; //! -//! fn query(&mut self) -> Result, OAuthError> { +//! // Declare the corresponding response type. +//! type Response = ExampleResponse; +//! +//! fn query(&mut self) -> Result, OAuthError> { //! Ok(Cow::Borrowed(&self.query)) //! } //! -//! fn urlbody(&mut self) -> Result, OAuthError> { +//! fn urlbody(&mut self) -> Result, OAuthError> { //! self.urlbody.as_ref() -//! .map(|body| Cow::Borrowed(body as &QueryParameter)) +//! .map(|body| Cow::Borrowed(body as &dyn QueryParameter)) //! .ok_or(OAuthError::PrimitiveError) //! } //! @@ -128,7 +128,7 @@ //! fn redirect(&mut self, target: Url) -> Result<(), OAuthError> { //! self.status = 302; //! self.www_authenticate = None; -//! self.location = Some(target.into_string()); +//! self.location = Some(target.into()); //! Ok(()) //! } //! diff --git a/oxide-auth/src/frontends/simple/endpoint.rs b/oxide-auth/src/frontends/simple/endpoint.rs index fe87bd5a..ce86951c 100644 --- a/oxide-auth/src/frontends/simple/endpoint.rs +++ b/oxide-auth/src/frontends/simple/endpoint.rs @@ -36,7 +36,7 @@ pub enum Error { /// A rather basic [`Endpoint`] implementation. /// -/// Substitue all parts that are not provided with the marker struct [`Vacant`]. This will at least +/// Substitute all parts that are not provided with the marker struct [`Vacant`]. This will at least /// ensure that no security properties are violated. Some flows may be unavailable when some /// primitives are missing. See [`AuthorizationFlow`], [`AccessTokenFlow`], [`ResourceFlow`] for /// more details. @@ -60,7 +60,7 @@ pub enum Error { /// ## Example /// /// Here is an example where a `Generic` is used to set up an endpoint that is filled with the -/// minimal members to be useable for an [`AccessTokenFlow`]. +/// minimal members to be usable for an [`AccessTokenFlow`]. /// /// ``` /// # extern crate oxide_auth; @@ -96,16 +96,16 @@ pub enum Error { /// [`ResourceFlow`]: ../../../endpoint/struct.ResourceFlow.html /// [`ResourceFlow`]: ../../../endpoint/trait.Scopes.html pub struct Generic { - /// The registrar implementation, or `Vacant` if it is not necesary. + /// The registrar implementation, or `Vacant` if it is not necessary. pub registrar: R, - /// The authorizer implementation, or `Vacant` if it is not necesary. + /// The authorizer implementation, or `Vacant` if it is not necessary. pub authorizer: A, - /// The issuer implementation, or `Vacant` if it is not necesary. + /// The issuer implementation, or `Vacant` if it is not necessary. pub issuer: I, - /// A solicitor implementation fit for the request types, or `Vacant` if it is not necesary. + /// A solicitor implementation fit for the request types, or `Vacant` if it is not necessary. pub solicitor: S, /// Determine scopes for the request types, or `Vacant` if this does not protect resources. @@ -151,7 +151,7 @@ impl ErrorInto { /// /// ## Scopes /// -/// Returns an empty list of scopes, effictively denying all requests since at least one scope +/// Returns an empty list of scopes, effectively denying all requests since at least one scope /// needs to be fulfilled by token to gain access. /// /// See [OwnerSolicitor](#OwnerSolicitor) for discussion on why this differs from the other @@ -487,7 +487,7 @@ impl Error { /// Convert into a single error type. /// /// Note that the additional information whether the error occurred in the web components or - /// during the flow needs to be implicitely contained in the types. Otherwise, this information + /// during the flow needs to be implicitly contained in the types. Otherwise, this information /// is lost and you should use or provide a `From>` implementation instead. This /// method is still useful for frontends providing a standard error type that interacts with /// their web server library. @@ -613,19 +613,19 @@ impl OptIssuer for T { impl OptRegistrar for Vacant { fn opt_ref(&self) -> Option<&dyn Registrar> { - Option::None + None } } impl OptAuthorizer for Vacant { fn opt_mut(&mut self) -> Option<&mut dyn Authorizer> { - Option::None + None } } impl OptIssuer for Vacant { fn opt_mut(&mut self) -> Option<&mut dyn Issuer> { - Option::None + None } } diff --git a/oxide-auth/src/frontends/simple/extensions/extended.rs b/oxide-auth/src/frontends/simple/extensions/extended.rs index 08e74f34..05a5bd94 100644 --- a/oxide-auth/src/frontends/simple/extensions/extended.rs +++ b/oxide-auth/src/frontends/simple/extensions/extended.rs @@ -26,7 +26,7 @@ impl Extended { } impl Extended { - /// Wrap an inner endpoint with a preconstructed extension instance. + /// Wrap an inner endpoint with a pre-constructed extension instance. pub fn extend_with(inner: Inner, extension: E) -> Self { Extended { inner, diff --git a/oxide-auth/src/frontends/simple/extensions/list.rs b/oxide-auth/src/frontends/simple/extensions/list.rs index 44604fd3..89ea07a4 100644 --- a/oxide-auth/src/frontends/simple/extensions/list.rs +++ b/oxide-auth/src/frontends/simple/extensions/list.rs @@ -2,12 +2,12 @@ use std::fmt; use std::sync::Arc; use super::{AuthorizationAddon, AccessTokenAddon, AddonResult}; -use crate::code_grant::accesstoken::{Extension as AccessTokenExtension, Request}; +use crate::code_grant::access_token::{Extension as AccessTokenExtension, Request}; use crate::code_grant::authorization::{Extension as AuthorizationExtension, Request as AuthRequest}; use crate::endpoint::Extension; use crate::primitives::grant::{Extensions, GrantExtension}; -/// A simple list of loosly related authorization and access addons. +/// A simple list of loosely related authorization and access addons. /// /// The owning representation of access extensions can be switched out to `Box<_>`, `Rc<_>` or /// other types. @@ -71,9 +71,7 @@ impl Extension for AddonList { } impl AccessTokenExtension for AddonList { - fn extend( - &mut self, request: &dyn Request, mut data: Extensions, - ) -> std::result::Result { + fn extend(&mut self, request: &dyn Request, mut data: Extensions) -> Result { let mut result_data = Extensions::new(); for ext in self.access_token.iter() { diff --git a/oxide-auth/src/frontends/simple/extensions/mod.rs b/oxide-auth/src/frontends/simple/extensions/mod.rs index cc9324c3..d9351834 100644 --- a/oxide-auth/src/frontends/simple/extensions/mod.rs +++ b/oxide-auth/src/frontends/simple/extensions/mod.rs @@ -2,7 +2,7 @@ //! //! Note that extensions will probably return in `v0.4` but not its preview versions. pub use crate::code_grant::authorization::Request as AuthorizationRequest; -pub use crate::code_grant::accesstoken::Request as AccessTokenRequest; +pub use crate::code_grant::access_token::Request as AccessTokenRequest; mod extended; mod pkce; @@ -40,7 +40,7 @@ pub trait AuthorizationAddon: GrantExtension { /// /// Derived information which needs to be bound to the returned grant can be stored in an /// encoded form by returning `Ok(extension_data)` while errors can be signaled via `Err(())`. - /// Extensions can also store their pure existance by initializing the extension struct without + /// Extensions can also store their pure existence by initializing the extension struct without /// data. Specifically, the data can be used in a corresponding `AccessTokenExtension`. fn execute(&self, request: &dyn AuthorizationRequest) -> AddonResult; } diff --git a/oxide-auth/src/frontends/simple/extensions/pkce.rs b/oxide-auth/src/frontends/simple/extensions/pkce.rs index 547eefa1..1a4f5b01 100644 --- a/oxide-auth/src/frontends/simple/extensions/pkce.rs +++ b/oxide-auth/src/frontends/simple/extensions/pkce.rs @@ -9,9 +9,9 @@ impl AuthorizationAddon for Pkce { let challenge = request.extension("code_challenge"); let encoded = match self.challenge(method, challenge) { - Err(()) => return AddonResult::Err, Ok(None) => return AddonResult::Ok, Ok(Some(encoded)) => encoded, + Err(_) => return AddonResult::Err, }; AddonResult::Data(encoded) diff --git a/oxide-auth/src/frontends/simple/mod.rs b/oxide-auth/src/frontends/simple/mod.rs index 245b8239..98780db3 100644 --- a/oxide-auth/src/frontends/simple/mod.rs +++ b/oxide-auth/src/frontends/simple/mod.rs @@ -1,4 +1,4 @@ -//! A baseline implemention of [`Endpoint`] and [`WebRequest`]. +//! A baseline implementation of [`Endpoint`] and [`WebRequest`]. //! //! Contains primitive extension implementations as well as straightforward request formats //! suitable for HTTP-less OAuth applications. This is useful for testing as well as token diff --git a/oxide-auth/src/frontends/simple/request.rs b/oxide-auth/src/frontends/simple/request.rs index dea62320..26a9202f 100644 --- a/oxide-auth/src/frontends/simple/request.rs +++ b/oxide-auth/src/frontends/simple/request.rs @@ -171,7 +171,7 @@ impl WebResponse for Response { Ok(()) } - /// Json repsonse data, with media type `aplication/json. + /// Json response data, with media type `application/json. fn body_json(&mut self, data: &str) -> Result<(), Self::Error> { self.body = Some(Body::Json(data.to_owned())); Ok(()) @@ -243,7 +243,7 @@ where self.0.body_text(text).map_err(&mut self.1) } - /// Json repsonse data, with media type `aplication/json. + /// Json response data, with media type `application/json`. fn body_json(&mut self, data: &str) -> Result<(), Self::Error> { self.0.body_json(data).map_err(&mut self.1) } diff --git a/oxide-auth/src/lib.rs b/oxide-auth/src/lib.rs index d283e97c..a35d7a8c 100644 --- a/oxide-auth/src/lib.rs +++ b/oxide-auth/src/lib.rs @@ -64,6 +64,10 @@ //! [`OwnerSolicitor`]: endpoint/trait.OwnerSolicitor.html //! [`Scopes`]: endpoint/trait.Scopes.html #![warn(missing_docs)] +#![warn(clippy::all)] +#![allow(clippy::module_name_repetitions)] +// TODO: remove this! +#![allow(clippy::result_unit_err)] pub mod code_grant; pub mod endpoint; diff --git a/oxide-auth/src/primitives/authorizer.rs b/oxide-auth/src/primitives/authorizer.rs index f7ede341..84da63ea 100644 --- a/oxide-auth/src/primitives/authorizer.rs +++ b/oxide-auth/src/primitives/authorizer.rs @@ -104,7 +104,7 @@ impl Authorizer for AuthMap { Ok(token) } - fn extract<'a>(&mut self, grant: &'a str) -> Result, ()> { + fn extract(&mut self, grant: &str) -> Result, ()> { Ok(self.tokens.remove(grant)) } } @@ -148,7 +148,7 @@ pub mod tests { // Authorize the same token again. let token_again = authorizer - .authorize(grant.clone()) + .authorize(grant) .expect("Authorization should not fail here"); // We don't produce the same token twice. assert_ne!(token, token_again); diff --git a/oxide-auth/src/primitives/generator.rs b/oxide-auth/src/primitives/generator.rs index a93aa1fb..d9693e82 100644 --- a/oxide-auth/src/primitives/generator.rs +++ b/oxide-auth/src/primitives/generator.rs @@ -161,7 +161,7 @@ impl Assertion { TaggedAssertion(self, tag) } - fn extract<'a>(&self, token: &'a str) -> Result<(Grant, String), ()> { + fn extract(&self, token: &str) -> Result<(Grant, String), ()> { let decoded = decode(token).map_err(|_| ())?; let assertion: AssertGrant = rmp_serde::from_slice(&decoded).map_err(|_| ())?; @@ -175,7 +175,7 @@ impl Assertion { Ok((serde_grant.grant(), tag)) } - fn signature(&self, data: &[u8]) -> Output> { + fn signature(&self, data: &[u8]) -> Output> { let mut hasher = self.hasher.clone(); hasher.update(data); hasher.finalize() @@ -214,7 +214,7 @@ impl<'a> TaggedAssertion<'a> { /// /// Result in an Err if either the signature is invalid or if the tag does not match the /// expected usage tag given to this assertion. - pub fn extract<'b>(&self, token: &'b str) -> Result { + pub fn extract(&self, token: &str) -> Result { self.0 .extract(token) .and_then(|(token, tag)| if tag == self.1 { Ok(token) } else { Err(()) }) @@ -304,7 +304,7 @@ mod url_serde { use serde::de::{Deserialize, Deserializer, Error}; pub fn serialize(url: &Url, serializer: S) -> Result { - serializer.serialize_str(&url.to_string()) + serializer.serialize_str(url.as_ref()) } pub fn deserialize<'de, D: Deserializer<'de>>(deserializer: D) -> Result { diff --git a/oxide-auth/src/primitives/grant.rs b/oxide-auth/src/primitives/grant.rs index 18a7e2aa..fc4a9462 100644 --- a/oxide-auth/src/primitives/grant.rs +++ b/oxide-auth/src/primitives/grant.rs @@ -1,4 +1,4 @@ -//! Encapsulates various shared mechanisms for handlings different grants. +//! Encapsulates various shared mechanisms for handling different grants. use super::{Url, Time}; use super::scope::Scope; @@ -29,7 +29,7 @@ pub enum Value { /// An extension that the token owner is allowed to read and interpret. Public(Option), - /// Identifies an extenion whose content and/or existance MUST be kept secret. + /// Identifies an extension whose content and/or existence MUST be kept secret. Private(Option), // Content which is not saved on the server but initialized/interpreted from other sources. // foreign_content: String, @@ -93,7 +93,7 @@ impl Value { /// but consists only of the key, and `Some(_)` otherwise. pub fn public_value(&self) -> Result, ()> { match self { - Value::Public(Some(content)) => Ok(Some(&content)), + Value::Public(Some(content)) => Ok(Some(content)), Value::Public(None) => Ok(None), _ => Err(()), } @@ -116,7 +116,7 @@ impl Value { /// but consists only of the key, and `Some(_)` otherwise. pub fn private_value(&self) -> Result, ()> { match self { - Value::Private(Some(content)) => Ok(Some(&content)), + Value::Private(Some(content)) => Ok(Some(content)), Value::Private(None) => Ok(None), _ => Err(()), } @@ -153,7 +153,7 @@ impl Extensions { /// Retrieve the stored data of an instance. /// - /// This removes the data from the store to avoid possible mixups and to allow a copyless + /// This removes the data from the store to avoid possible mix-ups and to allow a copyless /// retrieval of bigger data strings. pub fn remove(&mut self, extension: &dyn GrantExtension) -> Option { self.extensions.remove(extension.identifier()) diff --git a/oxide-auth/src/primitives/issuer.rs b/oxide-auth/src/primitives/issuer.rs index 98dbdaae..c6afe9d7 100644 --- a/oxide-auth/src/primitives/issuer.rs +++ b/oxide-auth/src/primitives/issuer.rs @@ -18,7 +18,7 @@ use super::generator::{TagGrant, TaggedAssertion, Assertion}; /// It's the issuers decision whether a refresh token is offered or not. In any case, it is also /// responsible for determining the validity and parameters of any possible token string. Some /// backends or frontends may decide not to propagate the refresh token (for example because -/// they do not intend to offer a statefull refresh api). +/// they do not intend to offer a stateful refresh api). pub trait Issuer { /// Create a token authorizing the request parameters fn issue(&mut self, grant: Grant) -> Result; @@ -189,7 +189,7 @@ impl IssuedToken { /// /// This is essential for issuers that can not revoke their tokens. Since refresh tokens are /// both long-lived and more powerful than their access token counterparts, it is more - /// dangerous to have an unrevokable refresh token. + /// dangerous to have an irrevocable refresh token. /// /// This is only a shorthand for initializing the `IssuedToken` with `None` for `refresh`. /// @@ -213,9 +213,9 @@ impl IssuedToken { /// Ok(IssuedToken::without_refresh(token, grant.until)) /// } /// // … + /// # fn refresh(&mut self, _: &str, _: Grant) -> Result { Err(()) } /// # fn recover_token<'t>(&'t self, token: &'t str) -> Result, ()> { Err(()) } /// # fn recover_refresh<'t>(&'t self, token: &'t str) -> Result, ()> { Err(()) } - /// # fn refresh(&mut self, _: &str, _: Grant) -> Result { Err(()) } /// } /// ``` pub fn without_refresh(token: String, until: Time) -> Self { @@ -248,11 +248,11 @@ impl Issuer for TokenMap { let access = self.generator.tag(self.usage, &grant)?; let refresh = self.generator.tag(self.usage.wrapping_add(1), &grant)?; debug_assert!( - access.len() > 0, + !access.is_empty(), "An empty access token was generated, this is horribly insecure." ); debug_assert!( - refresh.len() > 0, + !refresh.is_empty(), "An empty refresh token was generated, this is horribly insecure." ); (access, refresh) @@ -296,8 +296,8 @@ impl Issuer for TokenMap { let new_access_key: Arc = Arc::from(new_access.clone()); let new_refresh_key: Arc = Arc::from(new_refresh.clone()); - if let Some(atoken) = self.access.remove(&token.access) { - assert!(Arc::ptr_eq(&token, &atoken)); + if let Some(arc_token) = self.access.remove(&token.access) { + assert!(Arc::ptr_eq(&token, &arc_token)); } { @@ -388,7 +388,7 @@ impl TokenSigner { /// Determine whether to generate refresh tokens. /// /// By default, this option is *off*. Since the `TokenSigner` can on its own not revoke any - /// tokens it should be considered carefullly whether to issue very long-living and powerful + /// tokens it should be considered carefully whether to issue very long-living and powerful /// refresh tokens. On instance where this might be okay is as a component of a grander token /// architecture that adds a revocation mechanism. pub fn generate_refresh_tokens(&mut self, refresh: bool) { @@ -584,22 +584,22 @@ pub mod tests { pub fn simple_test_suite(issuer: &mut dyn Issuer) { let request = grant_template(); - let issued = issuer.issue(request.clone()).expect("Issuing failed"); + let issued_token = issuer.issue(request.clone()).expect("Issuing failed"); let from_token = issuer - .recover_token(&issued.token) + .recover_token(&issued_token.token) .expect("Issuer failed during recover") .expect("Issued token appears to be invalid"); - assert_ne!(Some(&issued.token), issued.refresh.as_ref()); + assert_ne!(Some(&issued_token.token), issued_token.refresh.as_ref()); assert_eq!(from_token.client_id, "Client"); assert_eq!(from_token.owner_id, "Owner"); assert!(Utc::now() < from_token.until); let issued_2 = issuer.issue(request).expect("Issuing failed"); - assert_ne!(issued.token, issued_2.token); - assert_ne!(Some(&issued.token), issued_2.refresh.as_ref()); - assert_ne!(issued.refresh, issued_2.refresh); - assert_ne!(issued.refresh.as_ref(), Some(&issued_2.token)); + assert_ne!(issued_token.token, issued_2.token); + assert_ne!(Some(&issued_token.token), issued_2.refresh.as_ref()); + assert_ne!(issued_token.refresh, issued_2.refresh); + assert_ne!(issued_token.refresh.as_ref(), Some(&issued_2.token)); } #[test] @@ -649,7 +649,7 @@ pub mod tests { let new_refresh = refreshed_token.refresh.expect("No new refresh token returned"); - assert!(refresh != new_refresh); + assert_ne!(refresh, new_refresh); } #[test] diff --git a/oxide-auth/src/primitives/mod.rs b/oxide-auth/src/primitives/mod.rs index 7351767d..68c51228 100644 --- a/oxide-auth/src/primitives/mod.rs +++ b/oxide-auth/src/primitives/mod.rs @@ -1,4 +1,4 @@ -//! A collection of primites useful for more than one authorization method. +//! A collection of primitives useful for more than one authorization method. //! //! A primitive is the smallest independent unit of policy used in OAuth related endpoints. For //! example, an `authorizer` generates and verifies Authorization Codes. There only is, as you diff --git a/oxide-auth/src/primitives/registrar.rs b/oxide-auth/src/primitives/registrar.rs index fa5e3ab7..ae2daffd 100644 --- a/oxide-auth/src/primitives/registrar.rs +++ b/oxide-auth/src/primitives/registrar.rs @@ -19,7 +19,7 @@ use rand::{RngCore, thread_rng}; use serde::{Deserialize, Serialize}; use url::{Url, ParseError as ParseUrlError}; -/// Registrars provie a way to interact with clients. +/// Registrars provide a way to interact with clients. /// /// Most importantly, they determine defaulted parameters for a request as well as the validity /// of provided parameters. In general, implementations of this trait will probably offer an @@ -101,7 +101,7 @@ impl<'de> Deserialize<'de> for ExactUrl { D: serde::Deserializer<'de>, { let string: &str = Deserialize::deserialize(deserializer)?; - core::str::FromStr::from_str(&string).map_err(serde::de::Error::custom) + core::str::FromStr::from_str(string).map_err(serde::de::Error::custom) } } @@ -127,7 +127,7 @@ impl<'de> Deserialize<'de> for ExactUrl { /// /// # Note /// -/// Local host ips (e.g. 127.0.0.1, [::1]) are treated as non-localhosts, so their ports are +/// Local host ips (e.g. 127.0.0.1, \[::1\]) are treated as non-localhosts, so their ports are /// considered. /// /// [`ExactUrl`]: ExactUrl @@ -207,7 +207,7 @@ pub struct PreGrant { /// Handled responses from a registrar. #[derive(Clone, Debug)] pub enum RegistrarError { - /// One of several different causes that should be indistiguishable. + /// One of several different causes that should be indistinguishable. /// /// * Indicates an entirely unknown client. /// * The client is not authorized. @@ -215,7 +215,7 @@ pub enum RegistrarError { /// exact match on the url, to prevent injection of bad query parameters for example but not /// strictly required. /// - /// These should be indistiguishable to avoid security problems. + /// These should be indistinguishable to avoid security problems. Unspecified, /// Something went wrong with this primitive that has no security reason. @@ -356,7 +356,7 @@ impl From for Url { /// Compares the registered url as an exact string if it was registered as exact, otherwise /// semantically. -impl cmp::PartialEq for RegisteredUrl { +impl PartialEq for RegisteredUrl { fn eq(&self, exact: &ExactUrl) -> bool { match self { RegisteredUrl::Exact(url) => url == exact, @@ -366,7 +366,7 @@ impl cmp::PartialEq for RegisteredUrl { } } -impl cmp::PartialEq for RegisteredUrl { +impl PartialEq for RegisteredUrl { fn eq(&self, ign_lport: &IgnoreLocalPortUrl) -> bool { match self { RegisteredUrl::Exact(url) => ign_lport == &IgnoreLocalPortUrl::from(url), @@ -377,7 +377,7 @@ impl cmp::PartialEq for RegisteredUrl { } /// Compares the registered url semantically. -impl cmp::PartialEq for RegisteredUrl { +impl PartialEq for RegisteredUrl { fn eq(&self, semantic: &Url) -> bool { self.to_url() == *semantic } @@ -570,7 +570,7 @@ impl<'a> RegisteredClient<'a> { } } -impl cmp::PartialOrd for PreGrant { +impl PartialOrd for PreGrant { /// `PreGrant` is compared by scope if `client_id` and `redirect_uri` are equal. fn partial_cmp(&self, rhs: &PreGrant) -> Option { if (&self.client_id, &self.redirect_uri) != (&rhs.client_id, &rhs.redirect_uri) { @@ -600,9 +600,11 @@ pub struct Argon2 { impl PasswordPolicy for Argon2 { fn store(&self, client_id: &str, passphrase: &[u8]) -> Vec { - let mut config = Config::default(); - config.ad = client_id.as_bytes(); - config.secret = &[]; + let config = Config { + ad: client_id.as_bytes(), + secret: &[], + ..Default::default() + }; let mut salt = vec![0; 32]; thread_rng() @@ -649,7 +651,7 @@ impl ClientMap { } // This is not an instance method because it needs to borrow the box but register needs &mut - fn current_policy<'a>(policy: &'a Option>) -> &'a dyn PasswordPolicy { + fn current_policy(policy: &Option>) -> &dyn PasswordPolicy { policy .as_ref() .map(|boxed| &**boxed) @@ -862,8 +864,7 @@ mod tests { .expect("Authorization of public client has changed"); registrar .check(public_id, Some(b"")) - .err() - .expect("Authorization with password succeeded"); + .expect_err("Authorization with password succeeded"); } let private_client = Client::confidential( @@ -881,8 +882,7 @@ mod tests { .expect("Authorization with right password did not succeed"); registrar .check(private_id, Some(b"Not the private passphrase")) - .err() - .expect("Authorization succeed with wrong password"); + .expect_err("Authorization succeed with wrong password"); } } diff --git a/oxide-auth/src/primitives/scope.rs b/oxide-auth/src/primitives/scope.rs index 2c85a555..fd397f46 100644 --- a/oxide-auth/src/primitives/scope.rs +++ b/oxide-auth/src/primitives/scope.rs @@ -72,20 +72,20 @@ impl Scope { fn invalid_scope_char(ch: char) -> bool { match ch { '\x21' => false, - ch if ch >= '\x23' && ch <= '\x5b' => false, - ch if ch >= '\x5d' && ch <= '\x7e' => false, - ' ' => false, // Space seperator is a valid char + ch if ('\x23'..='\x5b').contains(&ch) => false, + ch if ('\x5d'..='\x7e').contains(&ch) => false, + ' ' => false, // Space separator is a valid char _ => true, } } /// Determines if this scope has enough privileges to access some resource requiring the scope /// on the right side. This operation is equivalent to comparison via `>=`. - pub fn priviledged_to(&self, rhs: &Scope) -> bool { + pub fn privileged_to(&self, rhs: &Scope) -> bool { rhs <= self } - /// Determines if a resouce protected by this scope should allow access to a token with the + /// Determines if a resource protected by this scope should allow access to a token with the /// grant on the right side. This operation is equivalent to comparison via `<=`. pub fn allow_access(&self, rhs: &Scope) -> bool { self <= rhs @@ -154,7 +154,7 @@ impl fmt::Display for Scope { } } -impl cmp::PartialOrd for Scope { +impl PartialOrd for Scope { fn partial_cmp(&self, rhs: &Self) -> Option { let intersect_count = self.tokens.intersection(&rhs.tokens).count(); if intersect_count == self.tokens.len() && intersect_count == rhs.tokens.len() { @@ -202,16 +202,16 @@ mod tests { assert_eq!(scope_base.partial_cmp(&scope_base), Some(cmp::Ordering::Equal)); - assert!(scope_base.priviledged_to(&scope_less)); - assert!(scope_base.priviledged_to(&scope_base)); + assert!(scope_base.privileged_to(&scope_less)); + assert!(scope_base.privileged_to(&scope_base)); assert!(scope_less.allow_access(&scope_base)); assert!(scope_base.allow_access(&scope_base)); - assert!(!scope_less.priviledged_to(&scope_base)); + assert!(!scope_less.privileged_to(&scope_base)); assert!(!scope_base.allow_access(&scope_less)); - assert!(!scope_less.priviledged_to(&scope_uncmp)); - assert!(!scope_base.priviledged_to(&scope_uncmp)); + assert!(!scope_less.privileged_to(&scope_uncmp)); + assert!(!scope_base.privileged_to(&scope_uncmp)); assert!(!scope_uncmp.allow_access(&scope_less)); assert!(!scope_uncmp.allow_access(&scope_base)); }