feat: add group configuration (+)

will only check users of such group

also cleaned some code:
- Input doesn't need to be UTF-8 valid.
- Main fuction is dead-simple, very readable.
- Added some modularity.
- Add some docs on behavior details.
This commit is contained in:
2026-05-09 19:40:00 +02:00
parent d2a2baebc8
commit 0f736b1fc4
11 changed files with 224 additions and 81 deletions
+31 -4
View File
@@ -1,20 +1,25 @@
use std::{
ffi::OsStr,
ffi::{CStr, CString, OsStr},
fs::File,
io::{self},
os::unix::ffi::OsStrExt as _,
};
use curl::easy::{Easy, List};
use serde::Deserialize;
use crate::{ext::CStrExt as _, libc as mylibc};
mod api;
#[allow(clippy::unsafe_derive_deserialize)] // seriously? -_-
#[derive(Debug, Deserialize)]
pub struct KeycloakAPI {
base_url: String,
default_realm: String,
client_id: String,
client_secret: String,
unix_group: CString,
}
#[derive(Debug, thiserror::Error)]
@@ -68,13 +73,35 @@ impl KeycloakAPI {
Ok(serde_json::from_reader(f)?)
}
pub fn check_credentials(&self, username: &str, password: &str) -> Result<(), LoginError> {
pub fn should_skip(&self, username: &OsStr) -> Result<bool, mylibc::GetgrnamError> {
mylibc::getgrnam_use(&self.unix_group, |group| {
let mut members_ptr = group.gr_mem;
// SAFETY: The array pointer CANNOT be null, even if incremented.
while let member_cstr_ptr = unsafe { *members_ptr }
&& !member_cstr_ptr.is_null()
{
// SAFETY: its guaranteed to be a CStr and its non-null
let member_osstr = unsafe { CStr::from_ptr(member_cstr_ptr) }.to_os_str();
if member_osstr == username {
return false;
}
// SAFETY: if current pointer wasn't NULL, we can increase to the next one
members_ptr = unsafe { members_ptr.add(1) };
}
true
})
}
pub fn check_credentials(&self, username: &OsStr, password: &OsStr) -> Result<(), LoginError> {
let body = format!(
"grant_type=password&client_id={CLIENT_ID}&client_secret={CLIENT_SECRET}&username={USERNAME}&password={PASSWORD}",
CLIENT_ID = urlencoding::encode(&self.client_id),
CLIENT_SECRET = urlencoding::encode(&self.client_secret),
USERNAME = urlencoding::encode(username),
PASSWORD = urlencoding::encode(password),
USERNAME = urlencoding::encode_binary(username.as_bytes()),
PASSWORD = urlencoding::encode_binary(password.as_bytes()),
);
let (status_code, body) = curl_request(