create auth check helper function

This commit is contained in:
SeanOMik 2023-05-27 00:56:48 -04:00
parent e3a0554823
commit b5c770b349
Signed by: SeanOMik
GPG Key ID: 568F326C7EB33ACB
3 changed files with 42 additions and 23 deletions

View File

@ -8,7 +8,7 @@ use axum::response::{IntoResponse, Response};
use tokio_util::io::ReaderStream; use tokio_util::io::ReaderStream;
use crate::app_state::AppState; use crate::app_state::AppState;
use crate::auth_storage::{does_user_have_permission, get_unauthenticated_response}; use crate::auth_storage::{does_user_have_permission, get_unauthenticated_response, does_user_have_repository_permission};
use crate::database::Database; use crate::database::Database;
use crate::dto::RepositoryVisibility; use crate::dto::RepositoryVisibility;
use crate::dto::user::{Permission, RegistryUserType, UserAuth}; use crate::dto::user::{Permission, RegistryUserType, UserAuth};
@ -16,11 +16,14 @@ use crate::dto::user::{Permission, RegistryUserType, UserAuth};
pub async fn digest_exists_head(Path((name, layer_digest)): Path<(String, String)>, state: State<Arc<AppState>>, Extension(auth): Extension<UserAuth>) -> Response { pub async fn digest_exists_head(Path((name, layer_digest)): Path<(String, String)>, state: State<Arc<AppState>>, Extension(auth): Extension<UserAuth>) -> Response {
// Check if the user has permission to pull, or that the repository is public // Check if the user has permission to pull, or that the repository is public
let database = &state.database; let database = &state.database;
if !does_user_have_permission(database, auth.user.username, name.clone(), Permission::PULL).await.unwrap() /* if !does_user_have_permission(database, auth.user.username, name.clone(), Permission::PULL).await.unwrap()
&& !database.get_repository_visibility(&name).await.unwrap() && !database.get_repository_visibility(&name).await.unwrap()
.and_then(|v| Some(v == RepositoryVisibility::Public)) .and_then(|v| Some(v == RepositoryVisibility::Public))
.unwrap_or_else(|| false) { .unwrap_or_else(|| false) {
return get_unauthenticated_response(&state.config);
} */
if !does_user_have_repository_permission(database, auth.user.username, name.clone(), Permission::PULL, Some(RepositoryVisibility::Public)).await.unwrap() {
return get_unauthenticated_response(&state.config); return get_unauthenticated_response(&state.config);
} }
drop(database); drop(database);
@ -45,11 +48,7 @@ pub async fn digest_exists_head(Path((name, layer_digest)): Path<(String, String
pub async fn pull_digest_get(Path((name, layer_digest)): Path<(String, String)>, state: State<Arc<AppState>>, Extension(auth): Extension<UserAuth>) -> Response { pub async fn pull_digest_get(Path((name, layer_digest)): Path<(String, String)>, state: State<Arc<AppState>>, Extension(auth): Extension<UserAuth>) -> Response {
// Check if the user has permission to pull, or that the repository is public // Check if the user has permission to pull, or that the repository is public
let database = &state.database; let database = &state.database;
if !does_user_have_permission(database, auth.user.username, name.clone(), Permission::PULL).await.unwrap() if !does_user_have_repository_permission(database, auth.user.username, name.clone(), Permission::PULL, Some(RepositoryVisibility::Public)).await.unwrap() {
&& !database.get_repository_visibility(&name).await.unwrap()
.and_then(|v| Some(v == RepositoryVisibility::Public))
.unwrap_or_else(|| false) {
return get_unauthenticated_response(&state.config); return get_unauthenticated_response(&state.config);
} }
drop(database); drop(database);

View File

@ -7,7 +7,7 @@ use axum::http::{StatusCode, HeaderMap, HeaderName, header};
use tracing::log::warn; use tracing::log::warn;
use tracing::{debug, info}; use tracing::{debug, info};
use crate::auth_storage::{does_user_have_permission, get_unauthenticated_response}; use crate::auth_storage::{does_user_have_permission, get_unauthenticated_response, does_user_have_repository_permission};
use crate::app_state::AppState; use crate::app_state::AppState;
use crate::database::Database; use crate::database::Database;
use crate::dto::RepositoryVisibility; use crate::dto::RepositoryVisibility;
@ -64,11 +64,7 @@ pub async fn upload_manifest_put(Path((name, reference)): Path<(String, String)>
pub async fn pull_manifest_get(Path((name, reference)): Path<(String, String)>, state: State<Arc<AppState>>, Extension(auth): Extension<UserAuth>) -> Response { pub async fn pull_manifest_get(Path((name, reference)): Path<(String, String)>, state: State<Arc<AppState>>, Extension(auth): Extension<UserAuth>) -> Response {
// Check if the user has permission to pull, or that the repository is public // Check if the user has permission to pull, or that the repository is public
let database = &state.database; let database = &state.database;
if !does_user_have_permission(database, auth.user.username, name.clone(), Permission::PULL).await.unwrap() if !does_user_have_repository_permission(database, auth.user.username, name.clone(), Permission::PULL, Some(RepositoryVisibility::Public)).await.unwrap() {
&& !database.get_repository_visibility(&name).await.unwrap()
.and_then(|v| Some(v == RepositoryVisibility::Public))
.unwrap_or_else(|| false) {
return get_unauthenticated_response(&state.config); return get_unauthenticated_response(&state.config);
} }
drop(database); drop(database);
@ -111,11 +107,7 @@ pub async fn pull_manifest_get(Path((name, reference)): Path<(String, String)>,
pub async fn manifest_exists_head(Path((name, reference)): Path<(String, String)>, state: State<Arc<AppState>>, Extension(auth): Extension<UserAuth>) -> Response { pub async fn manifest_exists_head(Path((name, reference)): Path<(String, String)>, state: State<Arc<AppState>>, Extension(auth): Extension<UserAuth>) -> Response {
// Check if the user has permission to pull, or that the repository is public // Check if the user has permission to pull, or that the repository is public
let database = &state.database; let database = &state.database;
if !does_user_have_permission(database, auth.user.username, name.clone(), Permission::PULL).await.unwrap() if !does_user_have_repository_permission(database, auth.user.username, name.clone(), Permission::PULL, Some(RepositoryVisibility::Public)).await.unwrap() {
&& !database.get_repository_visibility(&name).await.unwrap()
.and_then(|v| Some(v == RepositoryVisibility::Public))
.unwrap_or_else(|| false) {
return get_unauthenticated_response(&state.config); return get_unauthenticated_response(&state.config);
} }
drop(database); drop(database);

View File

@ -4,7 +4,7 @@ use axum::{extract::{State, Path}, http::{StatusCode, HeaderMap, header, HeaderN
use tracing::debug; use tracing::debug;
use crate::{app_state::AppState, dto::user::{Permission, RegistryUserType}, config::Config}; use crate::{app_state::AppState, dto::{user::{Permission, RegistryUserType}, RepositoryVisibility}, config::Config};
use crate::database::Database; use crate::database::Database;
/// Temporary struct for storing auth information in memory. /// Temporary struct for storing auth information in memory.
@ -73,14 +73,42 @@ pub async fn require_auth<B>(State(state): State<Arc<AppState>>, mut request: Re
} }
} }
pub async fn does_user_have_permission(database: &impl Database, username: String, repository: String, permission: Permission) -> sqlx::Result<bool> { pub async fn does_user_have_permission(database: &impl Database, username: String, repository: String, permission: Permission) -> anyhow::Result<bool> {
does_user_have_repository_permission(database, username, repository, permission, None).await
}
/// Checks if a user has permission to do something in a repository.
///
/// * `database`: Database connection.
/// * `username`: Name of the user.
/// * `repository`: Name of the repository.
/// * `permissions`: Permission to check for.
/// * `required_visibility`: Specified if there is a specific visibility of the repository that will give the user permission.
pub async fn does_user_have_repository_permission(database: &impl Database, username: String, repository: String, permission: Permission, required_visibility: Option<RepositoryVisibility>) -> anyhow::Result<bool> {
let allowed_to = { let allowed_to = {
match database.get_user_registry_type(username.clone()).await.unwrap() { match database.get_user_registry_type(username.clone()).await? {
Some(RegistryUserType::Admin) => true, Some(RegistryUserType::Admin) => true,
_ => match database.get_user_repo_permissions(username, repository).await.unwrap() { _ => {
if let Some(perms) = database.get_user_repo_permissions(username, repository.clone()).await? {
if perms.has_permission(permission) {
return Ok(true);
}
}
if let Some(vis) = required_visibility {
if let Some(repo_vis) = database.get_repository_visibility(&repository).await? {
if vis == repo_vis {
return Ok(true);
}
}
}
false
}
/* match database.get_user_repo_permissions(username, repository).await.unwrap() {
Some(perms) => if perms.has_permission(permission) { true } else { false }, Some(perms) => if perms.has_permission(permission) { true } else { false },
_ => false, _ => false,
} } */
} }
}; };