diff --git a/crates/ldap/Cargo.toml b/crates/ldap/Cargo.toml new file mode 100644 index 0000000..a17c944 --- /dev/null +++ b/crates/ldap/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "ldap" +version = { workspace = true } +edition = { workspace = true } + +[dependencies] +actix-web = "4" +serde = { version = "1", features = ["derive"] } +ldap3 = "0.10" +tokio = { version = "1", features = ["full"] } +env_logger = "0.10" +log = "0.4" diff --git a/crates/ldap/src/ldap.rs b/crates/ldap/src/ldap.rs new file mode 100644 index 0000000..7030b63 --- /dev/null +++ b/crates/ldap/src/ldap.rs @@ -0,0 +1,63 @@ +use actix_web::{post, web, App, HttpResponse, HttpServer, Responder}; +use ldap3::{LdapConn, Scope, SearchEntry}; +use serde::Deserialize; +use std::env; + +// Struct to deserialize login request payload +#[derive(Deserialize)] +struct LoginRequest { + username: String, + password: String, +} + +// HTTP POST endpoint for user login +#[post("/login")] +async fn login(credentials: web::Json) -> impl Responder { + // Authenticate user and return appropriate response + match authenticate_user(&credentials.username, &credentials.password) { + Ok(true) => HttpResponse::Ok().body("Login erfolgreich"), // Login successful + _ => HttpResponse::Unauthorized().body("Login fehlgeschlagen"), // Login failed + } +} + +// Function to authenticate user against LDAP server +fn authenticate_user(username: &str, password: &str) -> Result> { + // Get LDAP server and base DN from environment variables or use defaults + let ldap_server = env::var("LDAP_SERVER").unwrap_or("ldap://127.0.0.1:389".to_string()); + let base_dn = env::var("LDAP_BASE_DN").unwrap_or("dc=schule,dc=local".to_string()); + + // Establish connection to LDAP server + let ldap = LdapConn::new(&ldap_server)?; + + // Search for the user in the LDAP directory + let (rs, _res) = ldap.search( + &format!("ou=users,{}", base_dn), // Search under "ou=users" + Scope::Subtree, // Search all levels + &format!("(uid={})", username), // Filter by username + vec!["dn"], // Retrieve the distinguished name (DN) + )?.success()?; + + // If user is found, attempt to authenticate with their DN and password + if let Some(entry) = rs.into_iter().next() { + let user_dn = SearchEntry::construct(entry).dn; // Extract user DN + + // Reconnect and bind with user credentials + let user_ldap = LdapConn::new(&ldap_server)?; + let auth_result = user_ldap.simple_bind(&user_dn, password)?.success(); + return Ok(auth_result.is_ok()); // Return true if authentication succeeds + } + + Ok(false) // Return false if user is not found +} + +// Main function to start the Actix Web server +#[actix_web::main] +async fn main() -> std::io::Result<()> { + env_logger::init(); // Initialize logger + + // Start HTTP server and bind to localhost:8080 + HttpServer::new(|| App::new().service(login)) + .bind(("127.0.0.1", 8080))? + .run() + .await +} \ No newline at end of file diff --git a/crates/ldap/src/user.ldif b/crates/ldap/src/user.ldif new file mode 100644 index 0000000..6a05bdb --- /dev/null +++ b/crates/ldap/src/user.ldif @@ -0,0 +1,29 @@ +dn: ou=users,dc=schule,dc=local +objectClass: organizationalUnit +ou: users + +dn: uid=schueler1,ou=users,dc=schule,dc=local +objectClass: inetOrgPerson +objectClass: posixAccount +objectClass: shadowAccount +cn: Schueler1 +sn: Mustermann +uid: schueler1 +uidNumber: 1001 +gidNumber: 1001 +homeDirectory: /home/schueler1 +loginShell: /bin/bash +userPassword: {SSHA}JDJhJDEwJG5EUFZ6U0pOSmpUckhOajRQY0hWNS5DNEp4Q2Mwa1pQSTZWYVhXeVdDMkFUMkFMY1do + +dn: uid=schueler2,ou=users,dc=schule,dc=local +objectClass: inetOrgPerson +objectClass: posixAccount +objectClass: shadowAccount +cn: Schueler2 +sn: Beispiel +uid: schueler2 +uidNumber: 1002 +gidNumber: 1002 +homeDirectory: /home/schueler2 +loginShell: /bin/bash +userPassword: {SSHA}JDJhJDEwJEpNVTRzNUk4Z3dQclA1M2o1bU5FZWZKeTRHTlVndXZ0Q0VhblBuNlZXUENyaFZ4Q3NmS2lH diff --git a/dev-compose.yml b/dev-compose.yml index 7ff9bc1..2b09296 100644 --- a/dev-compose.yml +++ b/dev-compose.yml @@ -36,6 +36,8 @@ services: volumes: - openldap_data:/var/lib/ldap - openldap_config:/etc/ldap/slapd.d + - users.ldif:/container/service/slapd/assets/config/bootstrap/ldif/custom/users.ldif + healthcheck: test: ["CMD", "ldapsearch", "-x", "-H", "ldap://localhost", "-b", "dc=Schule,dc=intern"] interval: 30s