summaryrefslogtreecommitdiff
path: root/src/lib.rs
diff options
context:
space:
mode:
authorJesse Morgan <jesse@jesterpm.net>2022-03-23 08:22:38 -0700
committerJesse Morgan <jesse@jesterpm.net>2022-03-23 08:22:38 -0700
commit3605650a90c0710aeee93930ba2622bf00a88b70 (patch)
tree80344b3717c3483cb1b07c9d1f7c8b6aa2a3199a /src/lib.rs
parent5ac0b170be23a2af4b93cb2287da1f7393db8165 (diff)
Add support for token extensionsv0.2.0
Diffstat (limited to 'src/lib.rs')
-rw-r--r--src/lib.rs106
1 files changed, 68 insertions, 38 deletions
diff --git a/src/lib.rs b/src/lib.rs
index 670a397..2584ab2 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -12,106 +12,128 @@
//!
//! # Example
//! ```
+//! # use std::future::Future;
//! # use actix_web::{ get, HttpResponse, HttpServer, Responder };
-//! # use actix_middleware_rfc7662::{AnyScope, RequireAuthorization, RequireAuthorizationConfig};
+//! # use actix_middleware_rfc7662::{AnyScope, RequireAuthorization, RequireAuthorizationConfig, StandardToken};
//!
//! #[get("/protected/api")]
//! async fn handle_read(_auth: RequireAuthorization<AnyScope>) -> impl Responder {
//! HttpResponse::Ok().body("Success!\n")
//! }
//!
-//! #[actix_web::main]
-//! async fn main() -> std::io::Result<()> {
-//! let oauth_config = RequireAuthorizationConfig::new(
+//! fn setup_server() -> std::io::Result<impl Future> {
+//! let oauth_config = RequireAuthorizationConfig::<StandardToken>::new(
//! "client_id".to_string(),
//! Some("client_secret".to_string()),
//! "https://example.com/oauth/authorize".parse().expect("invalid url"),
//! "https://example.com/oauth/introspect".parse().expect("invalid url"),
//! );
//!
-//! HttpServer::new(move || {
+//! Ok(HttpServer::new(move || {
//! actix_web::App::new()
//! .app_data(oauth_config.clone())
//! .service(handle_read)
-//! .service(handle_write)
//! })
//! .bind("127.0.0.1:8182".to_string())?
-//! .run()
-//! .await
+//! .run())
//! }
//! ```
use actix_web::{dev, FromRequest, HttpRequest};
use futures_util::future::LocalBoxFuture;
-use oauth2::basic::{BasicErrorResponseType, BasicTokenType};
+use oauth2::basic::BasicErrorResponseType;
use oauth2::url::Url;
-use oauth2::*;
+use oauth2::{
+ reqwest, AccessToken, AuthUrl, ClientId, ClientSecret, IntrospectionUrl, StandardErrorResponse,
+ StandardRevocableToken, StandardTokenResponse, TokenIntrospectionResponse,
+};
use std::future::ready;
use std::marker::PhantomData;
use std::sync::Arc;
+// Re-exports
+pub use oauth2::{
+ basic::BasicTokenType, EmptyExtraTokenFields as StandardToken, ExtraTokenFields,
+ StandardTokenIntrospectionResponse,
+};
+
mod error;
-use error::Error;
+
+#[cfg(feature = "indieauth")]
+pub mod indieauth;
+
+pub use error::Error;
const BEARER_TOKEN_PREFIX: &str = "Bearer ";
-pub type IntrospectionResponse =
- StandardTokenIntrospectionResponse<EmptyExtraTokenFields, BasicTokenType>;
+pub type IntrospectionResponse<T> = StandardTokenIntrospectionResponse<T, BasicTokenType>;
-pub trait AuthorizationRequirements {
- fn authorized(introspection: &IntrospectionResponse) -> Result<bool, Error>;
+pub trait AuthorizationRequirements<T>
+where
+ T: ExtraTokenFields,
+{
+ fn authorized(introspection: &IntrospectionResponse<T>) -> Result<bool, Error>;
}
pub trait RequireScope {
fn scope() -> &'static str;
}
-impl<T> AuthorizationRequirements for T
+impl<T, S> AuthorizationRequirements<T> for S
where
- T: RequireScope,
+ S: RequireScope,
+ T: ExtraTokenFields,
{
- fn authorized(introspection: &IntrospectionResponse) -> Result<bool, Error> {
+ fn authorized(introspection: &IntrospectionResponse<T>) -> Result<bool, Error> {
Ok(introspection
.scopes()
- .map(|s| s.iter().find(|s| s.as_ref() == T::scope()).is_some())
+ .map(|s| s.iter().find(|s| s.as_ref() == S::scope()).is_some())
.unwrap_or(false))
}
}
pub struct AnyScope;
-impl AuthorizationRequirements for AnyScope {
- fn authorized(_: &IntrospectionResponse) -> Result<bool, Error> {
+impl<T> AuthorizationRequirements<T> for AnyScope
+where
+ T: ExtraTokenFields,
+{
+ fn authorized(_: &IntrospectionResponse<T>) -> Result<bool, Error> {
Ok(true)
}
}
-pub struct RequireAuthorization<T>
+pub struct RequireAuthorization<R, T = StandardToken>
where
- T: AuthorizationRequirements,
+ R: AuthorizationRequirements<T>,
+ T: ExtraTokenFields,
{
- introspection: IntrospectionResponse,
- _auth_marker: PhantomData<T>,
+ introspection: IntrospectionResponse<T>,
+ _auth_marker: PhantomData<R>,
}
-impl<T> RequireAuthorization<T>
+impl<R, T> RequireAuthorization<R, T>
where
- T: AuthorizationRequirements,
+ R: AuthorizationRequirements<T>,
+ T: ExtraTokenFields,
{
- pub fn introspection(&self) -> &IntrospectionResponse {
+ pub fn introspection(&self) -> &IntrospectionResponse<T> {
&self.introspection
}
}
-impl<T> FromRequest for RequireAuthorization<T>
+impl<R, T> FromRequest for RequireAuthorization<R, T>
where
- T: AuthorizationRequirements + 'static,
+ R: AuthorizationRequirements<T> + 'static,
+ T: ExtraTokenFields + 'static + Clone,
{
type Error = Error;
type Future = LocalBoxFuture<'static, Result<Self, Self::Error>>;
fn from_request(req: &actix_web::HttpRequest, _: &mut dev::Payload) -> Self::Future {
- let verifier = if let Some(verifier) = req.app_data::<RequireAuthorizationConfig>() {
+ let my_req2 = req.clone();
+
+ let verifier = if let Some(verifier) = my_req2.app_data::<RequireAuthorizationConfig<T>>() {
verifier.clone()
} else {
return Box::pin(ready(Err(Error::ConfigurationError)));
@@ -124,7 +146,7 @@ where
.verify_request(my_req)
.await
.and_then(|introspection| {
- if T::authorized(&introspection)? {
+ if R::authorized(&introspection)? {
Ok(RequireAuthorization {
introspection,
_auth_marker: PhantomData::default(),
@@ -138,21 +160,29 @@ where
}
#[derive(Clone)]
-struct RequireAuthorizationConfigInner {
+struct RequireAuthorizationConfigInner<T>
+where
+ T: ExtraTokenFields,
+{
client: oauth2::Client<
StandardErrorResponse<BasicErrorResponseType>,
- StandardTokenResponse<EmptyExtraTokenFields, BasicTokenType>,
+ StandardTokenResponse<T, BasicTokenType>,
BasicTokenType,
- StandardTokenIntrospectionResponse<EmptyExtraTokenFields, BasicTokenType>,
+ StandardTokenIntrospectionResponse<T, BasicTokenType>,
StandardRevocableToken,
StandardErrorResponse<BasicErrorResponseType>,
>,
}
#[derive(Clone)]
-pub struct RequireAuthorizationConfig(Arc<RequireAuthorizationConfigInner>);
+pub struct RequireAuthorizationConfig<T>(Arc<RequireAuthorizationConfigInner<T>>)
+where
+ T: ExtraTokenFields;
-impl RequireAuthorizationConfig {
+impl<T> RequireAuthorizationConfig<T>
+where
+ T: ExtraTokenFields,
+{
pub fn new(
client_id: String,
client_secret: Option<String>,
@@ -169,7 +199,7 @@ impl RequireAuthorizationConfig {
RequireAuthorizationConfig(Arc::new(RequireAuthorizationConfigInner { client }))
}
- async fn verify_request(&self, req: HttpRequest) -> Result<IntrospectionResponse, Error> {
+ async fn verify_request(&self, req: HttpRequest) -> Result<IntrospectionResponse<T>, Error> {
let access_token = req
.headers()
.get("Authorization")