implement admin login

This commit is contained in:
Ilion Beyst 2022-06-27 21:20:05 +02:00
parent f6fca3818a
commit d7e4a1fd5c

View file

@ -52,10 +52,15 @@ async fn fallback(request: axum::http::Request<Body>) -> impl IntoResponse {
StatusCode::NOT_FOUND StatusCode::NOT_FOUND
} }
const ADMIN_USERNAME: &str = "admin";
// TODO: put this in some configuration
const ADMIN_PASSWORD: &str = "supersecretpassword";
type AuthorizationHeader = TypedHeader<Authorization<Basic>>; type AuthorizationHeader = TypedHeader<Authorization<Basic>>;
enum RegistryAuth { enum RegistryAuth {
User(User), User(User),
Admin,
} }
enum RegistryAuthError { enum RegistryAuthError {
@ -94,8 +99,6 @@ where
type Rejection = RegistryAuthError; type Rejection = RegistryAuthError;
async fn from_request(req: &mut RequestParts<B>) -> Result<Self, Self::Rejection> { async fn from_request(req: &mut RequestParts<B>) -> Result<Self, Self::Rejection> {
let db_conn = DatabaseConnection::from_request(req).await.unwrap();
let TypedHeader(Authorization(basic)) = AuthorizationHeader::from_request(req) let TypedHeader(Authorization(basic)) = AuthorizationHeader::from_request(req)
.await .await
.map_err(|_| RegistryAuthError::NoAuthHeader)?; .map_err(|_| RegistryAuthError::NoAuthHeader)?;
@ -105,12 +108,22 @@ where
username: basic.username(), username: basic.username(),
password: basic.password(), password: basic.password(),
}; };
if credentials.username == ADMIN_USERNAME {
if credentials.password == ADMIN_PASSWORD {
Ok(RegistryAuth::Admin)
} else {
Err(RegistryAuthError::InvalidCredentials)
}
} else {
let db_conn = DatabaseConnection::from_request(req).await.unwrap();
let user = authenticate_user(&credentials, &db_conn) let user = authenticate_user(&credentials, &db_conn)
.ok_or(RegistryAuthError::InvalidCredentials)?; .ok_or(RegistryAuthError::InvalidCredentials)?;
Ok(RegistryAuth::User(user)) Ok(RegistryAuth::User(user))
} }
} }
}
async fn get_root(_auth: RegistryAuth) -> impl IntoResponse { async fn get_root(_auth: RegistryAuth) -> impl IntoResponse {
// root should return 200 OK to confirm api compliance // root should return 200 OK to confirm api compliance
@ -348,6 +361,8 @@ async fn put_manifest(
.unwrap()) .unwrap())
} }
/// Ensure that the accessed repository exists
/// and the user is allowed to access ti
fn check_access( fn check_access(
repository_name: &str, repository_name: &str,
auth: &RegistryAuth, auth: &RegistryAuth,
@ -355,15 +370,17 @@ fn check_access(
) -> Result<(), StatusCode> { ) -> Result<(), StatusCode> {
use diesel::OptionalExtension; use diesel::OptionalExtension;
let res = db::bots::find_bot_by_name(repository_name, db_conn) // TODO: it would be nice to provide the found repository
// to the route handlers
let bot = db::bots::find_bot_by_name(repository_name, db_conn)
.optional() .optional()
.expect("could not run query"); .expect("could not run query")
.ok_or(StatusCode::NOT_FOUND)?;
match res { match &auth {
None => Err(StatusCode::FORBIDDEN), RegistryAuth::Admin => Ok(()),
Some(existing_bot) => { RegistryAuth::User(user) => {
let RegistryAuth::User(user) = auth; if bot.owner_id == Some(user.id) {
if existing_bot.owner_id == Some(user.id) {
Ok(()) Ok(())
} else { } else {
Err(StatusCode::FORBIDDEN) Err(StatusCode::FORBIDDEN)