Skip to content

Commit

Permalink
Cleanup and refactor of auth crate
Browse files Browse the repository at this point in the history
  • Loading branch information
danielalvsaaker committed Aug 18, 2022
1 parent 9c4fb0f commit 2f0b404
Show file tree
Hide file tree
Showing 24 changed files with 859 additions and 444 deletions.
3 changes: 3 additions & 0 deletions crates/tf-auth/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@ edition = "2021"
askama = { version = "0.11", features = ["with-axum"] }
askama_axum = "0.1"

async-trait = "0.1"
argon2 = { version = "0.4", features = ["std"] }
oxide-auth = "0.5"
oxide-auth-axum = "0.2"
oxide-auth-async = "0.1"
axum = { version = "0.5", features = ["headers"] }
thiserror = "1"
serde = { version = "1", features = ["derive"] }
Expand All @@ -18,3 +20,4 @@ nanoid = "0.4"
async-session = "3"
tf-models = { path = "../tf-models" }
tf-database = { path = "../tf-database" }
tokio = { version = "1", features = ["sync"] }
111 changes: 16 additions & 95 deletions crates/tf-auth/src/database/mod.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,13 @@
use crate::error::Result;
use oxide_auth::primitives::{registrar::Client, scope::Scope};

pub mod resources;
pub mod resource;

use resources::{EncodedClient, User};
use std::borrow::Cow;
use tf_database::{
primitives::Key,
query::{ClientQuery, UserQuery},
};

use oxide_auth::primitives::registrar::{
Argon2, BoundClient, ClientUrl, PreGrant, RegisteredClient, Registrar, RegistrarError,
use oxide_auth::primitives::registrar::{Argon2, Client};
use resource::{
client::{ClientName, EncodedClient},
user::User,
};
use tf_database::query::{ClientQuery, UserQuery};

#[derive(Clone)]
pub struct Database {
Expand All @@ -26,86 +21,6 @@ impl std::ops::Deref for Database {
&self.inner
}
}

impl Registrar for Database {
fn bound_redirect<'a>(&self, bound: ClientUrl<'a>) -> Result<BoundClient<'a>, RegistrarError> {
let client = self
.inner
.root::<User>()
.map_err(|_| RegistrarError::PrimitiveError)?
.traverse::<EncodedClient>()
.map_err(|_| RegistrarError::PrimitiveError)?
.get(
&ClientQuery::from_bytes(bound.client_id.as_bytes())
.map_err(|_| RegistrarError::Unspecified)?,
)
.map_err(|_| RegistrarError::PrimitiveError)?
.ok_or(RegistrarError::Unspecified)?
.inner;

let registered_url = match bound.redirect_uri {
None => client.redirect_uri,
Some(ref url) => {
let original = std::iter::once(&client.redirect_uri);
let alternatives = client.additional_redirect_uris.iter();

original
.chain(alternatives)
.find(|&registered| *registered == *url.as_ref())
.cloned()
.ok_or(RegistrarError::Unspecified)?
}
};

Ok(BoundClient {
client_id: bound.client_id,
redirect_uri: Cow::Owned(registered_url),
})
}

fn negotiate(
&self,
bound: BoundClient,
_scope: Option<Scope>,
) -> Result<PreGrant, RegistrarError> {
let client = self
.inner
.root::<User>()
.map_err(|_| RegistrarError::PrimitiveError)?
.traverse::<EncodedClient>()
.map_err(|_| RegistrarError::PrimitiveError)?
.get(&ClientQuery::from_bytes(bound.client_id.as_bytes()).unwrap())
.map_err(|_| RegistrarError::PrimitiveError)?
.map(|x| x.inner)
.unwrap();

Ok(PreGrant {
client_id: bound.client_id.into_owned(),
redirect_uri: bound.redirect_uri.into_owned(),
scope: client.default_scope,
})
}

fn check(&self, client_id: &str, passphrase: Option<&[u8]>) -> Result<(), RegistrarError> {
let password_policy = Argon2::default();

self.inner
.root::<User>()
.map_err(|_| RegistrarError::PrimitiveError)?
.traverse::<EncodedClient>()
.map_err(|_| RegistrarError::PrimitiveError)?
.get(&ClientQuery::from_bytes(client_id.as_bytes()).unwrap())
.map_err(|_| RegistrarError::PrimitiveError)?
.ok_or(RegistrarError::Unspecified)
.map(|x| x.inner)
.and_then(|client| {
RegisteredClient::new(&client, &password_policy).check_authentication(passphrase)
})?;

Ok(())
}
}

impl Database {
pub fn open<P>(path: P) -> Result<Self>
where
Expand All @@ -120,15 +35,21 @@ impl Database {
&self,
query: &ClientQuery,
client: Client,
client_name: String,
user: &UserQuery,
) -> Result<()> {
let inner = client.encode(&Argon2::default());
let client = EncodedClient { inner };

self.inner
.root::<User>()?
.traverse::<EncodedClient>()?
.insert(query, &client, user)?;
let collection = self.inner.root::<User>()?.traverse::<EncodedClient>()?;

collection.insert(query, &client, user)?;

collection.traverse::<ClientName>(query)?.insert(
query,
&ClientName { inner: client_name },
query,
)?;

Ok(())
}
Expand Down
29 changes: 29 additions & 0 deletions crates/tf-auth/src/database/resource/client.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
use oxide_auth::primitives::registrar::EncodedClient as Inner;
use serde::{Deserialize, Serialize};
use tf_database::{primitives::Relation, query::ClientQuery, resource::Resource, Traverse};

#[derive(Serialize, Deserialize)]
pub struct EncodedClient {
pub inner: Inner,
}

impl Resource for EncodedClient {
const NAME: &'static str = "client";

type Key = ClientQuery;
}

impl Traverse<ClientName> for EncodedClient {
type Collection = Relation<ClientQuery, ClientName, ClientQuery, EncodedClient>;
}

#[derive(Serialize, Deserialize)]
pub struct ClientName {
pub inner: String,
}

impl Resource for ClientName {
const NAME: &'static str = "client_name";

type Key = ClientQuery;
}
2 changes: 2 additions & 0 deletions crates/tf-auth/src/database/resource/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
pub mod client;
pub mod user;
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use oxide_auth::primitives::registrar::EncodedClient as Inner;
use super::client::EncodedClient;
use serde::{Deserialize, Serialize};
use tf_database::{
primitives::{Index, Relation},
Expand All @@ -7,17 +7,22 @@ use tf_database::{
Traverse,
};

#[derive(Serialize, Deserialize)]
pub struct EncodedClient {
pub inner: Inner,
}

#[derive(Serialize, Deserialize)]
pub struct User {
pub username: String,
pub password: String,
}

impl Resource for User {
const NAME: &'static str = "user";

type Key = UserQuery;
}

impl Traverse<EncodedClient> for User {
type Collection = Relation<ClientQuery, EncodedClient, UserQuery, User>;
}

#[derive(Serialize, Deserialize)]
pub struct Username;

Expand All @@ -30,19 +35,3 @@ impl Resource for Username {
impl Traverse<User> for Username {
type Collection = Index<String, Username, UserQuery, User>;
}

impl Resource for EncodedClient {
const NAME: &'static str = "client";

type Key = ClientQuery;
}

impl Resource for User {
const NAME: &'static str = "user";

type Key = UserQuery;
}

impl Traverse<EncodedClient> for User {
type Collection = Relation<ClientQuery, EncodedClient, UserQuery, User>;
}
63 changes: 63 additions & 0 deletions crates/tf-auth/src/endpoint/extension.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
use oxide_auth::{
code_grant::{
accesstoken::Request as AccessTokenRequest, authorization::Request as AuthorizationRequest,
},
endpoint,
frontends::simple::extensions,
primitives::grant::Extensions,
};
use oxide_auth_async::endpoint::{AccessTokenExtension, AuthorizationExtension, Extension};

pub struct Empty;

impl Extension for Empty {}

#[derive(Default)]
pub struct AddonList {
inner: extensions::AddonList,
}

impl std::ops::Deref for AddonList {
type Target = extensions::AddonList;

fn deref(&self) -> &Self::Target {
&self.inner
}
}

impl std::ops::DerefMut for AddonList {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.inner
}
}

#[async_trait::async_trait]
impl AuthorizationExtension for AddonList {
async fn extend(
&mut self,
request: &(dyn AuthorizationRequest + Sync),
) -> std::result::Result<Extensions, ()> {
endpoint::AuthorizationExtension::extend(&mut self.inner, request)
}
}

#[async_trait::async_trait]
impl AccessTokenExtension for AddonList {
async fn extend(
&mut self,
request: &(dyn AccessTokenRequest + Sync),
data: Extensions,
) -> std::result::Result<Extensions, ()> {
endpoint::AccessTokenExtension::extend(&mut self.inner, request, data)
}
}

impl Extension for AddonList {
fn authorization(&mut self) -> Option<&mut (dyn AuthorizationExtension + Send)> {
Some(self)
}

fn access_token(&mut self) -> Option<&mut (dyn AccessTokenExtension + Send)> {
Some(self)
}
}
Loading

0 comments on commit 2f0b404

Please sign in to comment.