Repository: meilisearch/meilisearch
File: meilisearch-http/src/extractors/authentication/mod.rs (Rust)

Code before:
            Some(filters) => match data {
                Some(data) => Ok(Self {
                    data,
                    filters,
                    _marker: PhantomData,
                }),
                None => Err(AuthenticationError::IrretrievableState.into()),
            },
            None => Err(AuthenticationError::InvalidToken.into()),
        }
    }

    async fn auth_token(auth: AuthController, data: Option<D>) -> Result<Self, ResponseError>
    where
        P: Policy + 'static,
    {
        match Self::authenticate(auth, String::new(), None).await? {
            Some(filters) => match data {
                Some(data) => Ok(Self {
                    data,
                    filters,
                    _marker: PhantomData,
                }),
                None => Err(AuthenticationError::IrretrievableState.into()),
            },
            None => Err(AuthenticationError::MissingMasterKey.into()),
        }
    }

    async fn authenticate(
        auth: AuthController,
        token: String,
        index: Option<String>,
    ) -> Result<Option<AuthFilter>, ResponseError>
    where
        P: Policy + 'static,
    {
        tokio::task::spawn_blocking(move || P::authenticate(auth, token.as_ref(), index.as_deref()))
            .await
            .map_err(|e| ResponseError::from_msg(e.to_string(), Code::Internal))
    }
}

impl<P, D> Deref for GuardedData<P, D> {
    type Target = D;

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


Review comment (security):
> Any hints as to where should the change be made?

I would say that this is your issue. `Self::authenticate` don't return `None` only because there is no master key. I suggest changing the return value of `Self::authenticate` in order to make the difference; OR the `auth: AuthController` can inform you if a master key is set, matching on it could be a solution.

Code after:
            Some(filters) => match data {
                Some(data) => Ok(Self {
                    data,
                    filters,
                    _marker: PhantomData,
                }),
                None => Err(AuthenticationError::IrretrievableState.into()),
            },
            None => Err(AuthenticationError::InvalidToken.into()),
        }
    }

    async fn auth_token(auth: AuthController, data: Option<D>) -> Result<Self, ResponseError>
    where
        P: Policy + 'static,
    {
        let missing_master_key = auth.get_master_key().is_none();

        match Self::authenticate(auth, String::new(), None).await? {
            Some(filters) => match data {
                Some(data) => Ok(Self {
                    data,
                    filters,
                    _marker: PhantomData,
                }),

                None => Err(AuthenticationError::IrretrievableState.into()),
            },
            None if missing_master_key => Err(AuthenticationError::MissingMasterKey.into()),
            None => Err(AuthenticationError::MissingAuthorizationHeader.into()),
        }
    }

    async fn authenticate(
        auth: AuthController,
        token: String,
        index: Option<String>,
    ) -> Result<Option<AuthFilter>, ResponseError>
    where
        P: Policy + 'static,
    {
        tokio::task::spawn_blocking(move || P::authenticate(auth, token.as_ref(), index.as_deref()))
            .await
            .map_err(|e| ResponseError::from_msg(e.to_string(), Code::Internal))
    }
}

impl<P, D> Deref for GuardedData<P, D> {
    type Target = D;

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