8 Commits
v0.6.1 ... main

Author SHA1 Message Date
Valentin Tolmer
f417427635 Prevent starting up if the JWT secret is not given
Similarly, don't create the admin if the password is not given
2024-12-24 19:40:26 +01:00
Dakota G
1f26262e13 example_configs: add Hashicorp 2024-12-10 07:34:50 +01:00
Zepmann
42fccf4713 readme: Updated Arch Linux install-from-repository section
Cleaned up the Arch Linux section. Added a link to the discussions support thread.
2024-12-07 18:49:58 +01:00
xeoneox
928faa4bcc example_configs: add search filter in onedev configuration 2024-12-07 07:17:52 +01:00
xeoneox
3895a5050d example_configs: Update OneDev example for latest release 2024-12-06 00:21:35 +01:00
Christian Medel
f92035b6fd example_configs: Add Kimai 2024-11-25 22:20:09 +01:00
Valentin Tolmer
37a10c871f github: Fix release bot clearing the release body 2024-11-22 23:12:36 +01:00
Valentin Tolmer
8397d536d9 chore: bump version to 0.6.2-alpha 2024-11-22 22:55:53 +01:00
15 changed files with 254 additions and 62 deletions

View File

@@ -216,6 +216,8 @@ jobs:
LLDAP_database_url: postgres://lldapuser:lldappass@localhost/lldap
LLDAP_ldap_port: 3890
LLDAP_http_port: 17170
LLDAP_JWT_SECRET: verysecret
LLDAP_LDAP_USER_PASS: password
- name: Run lldap with mariadb DB (MySQL Compatible) and healthcheck
@@ -227,6 +229,8 @@ jobs:
LLDAP_database_url: mysql://lldapuser:lldappass@localhost/lldap
LLDAP_ldap_port: 3891
LLDAP_http_port: 17171
LLDAP_JWT_SECRET: verysecret
LLDAP_LDAP_USER_PASS: password
- name: Run lldap with sqlite DB and healthcheck
@@ -238,6 +242,8 @@ jobs:
LLDAP_database_url: sqlite://users.db?mode=rwc
LLDAP_ldap_port: 3892
LLDAP_http_port: 17172
LLDAP_JWT_SECRET: verysecret
LLDAP_LDAP_USER_PASS: password
- name: Check DB container logs
run: |
@@ -324,9 +330,9 @@ jobs:
sleep 10s
bin/lldap healthcheck
env:
LLDAP_database_url: sqlite://users.db?mode=rwc
LLDAP_ldap_port: 3890
LLDAP_http_port: 17170
LLDAP_DATABASE_URL: sqlite://users.db?mode=rwc
LLDAP_LDAP_PORT: 3890
LLDAP_HTTP_PORT: 17170
LLDAP_LDAP_USER_PASS: ldappass
LLDAP_JWT_SECRET: somejwtsecret
@@ -350,8 +356,11 @@ jobs:
sed -i -r -e "s/X'([[:xdigit:]]+'[^'])/'\\\x\\1/g" -e ":a; s/(INSERT INTO (user_attribute_schema|jwt_storage)\(.*\) VALUES\(.*),1([^']*\);)$/\1,true\3/; s/(INSERT INTO (user_attribute_schema|jwt_storage)\(.*\) VALUES\(.*),0([^']*\);)$/\1,false\3/; ta" -e '1s/^/BEGIN;\n/' -e '$aCOMMIT;' ./dump.sql
- name: Create schema on postgres
env:
LLDAP_DATABASE_URL: postgres://lldapuser:lldappass@localhost:5432/lldap
LLDAP_JWT_SECRET: somejwtsecret
run: |
bin/lldap create_schema -d postgres://lldapuser:lldappass@localhost:5432/lldap
bin/lldap create_schema
- name: Copy converted db to postgress and import
run: |
@@ -368,7 +377,10 @@ jobs:
sed -i '1 i\SET FOREIGN_KEY_CHECKS = 0;' ./dump.sql
- name: Create schema on mariadb
run: bin/lldap create_schema -d mysql://lldapuser:lldappass@localhost:3306/lldap
env:
LLDAP_DATABASE_URL: mysql://lldapuser:lldappass@localhost:3306/lldap
LLDAP_JWT_SECRET: somejwtsecret
run: bin/lldap create_schema
- name: Copy converted db to mariadb and import
run: |
@@ -384,7 +396,10 @@ jobs:
sed -i '1 i\SET FOREIGN_KEY_CHECKS = 0;' ./dump.sql
- name: Create schema on mysql
run: bin/lldap create_schema -d mysql://lldapuser:lldappass@localhost:3307/lldap
env:
LLDAP_DATABASE_URL: mysql://lldapuser:lldappass@localhost:3307/lldap
LLDAP_JWT_SECRET: somejwtsecret
run: bin/lldap create_schema
- name: Copy converted db to mysql and import
run: |
@@ -399,10 +414,9 @@ jobs:
sleep 10s
bin/lldap healthcheck
env:
LLDAP_database_url: postgres://lldapuser:lldappass@localhost:5432/lldap
LLDAP_ldap_port: 3891
LLDAP_http_port: 17171
LLDAP_LDAP_USER_PASS: ldappass
LLDAP_DATABASE_URL: postgres://lldapuser:lldappass@localhost:5432/lldap
LLDAP_LDAP_PORT: 3891
LLDAP_HTTP_PORT: 17171
LLDAP_JWT_SECRET: somejwtsecret
- name: Run lldap with mariaDB and healthcheck again
@@ -411,9 +425,9 @@ jobs:
sleep 10s
bin/lldap healthcheck
env:
LLDAP_database_url: mysql://lldapuser:lldappass@localhost:3306/lldap
LLDAP_ldap_port: 3892
LLDAP_http_port: 17172
LLDAP_DATABASE_URL: mysql://lldapuser:lldappass@localhost:3306/lldap
LLDAP_LDAP_PORT: 3892
LLDAP_HTTP_PORT: 17172
LLDAP_JWT_SECRET: somejwtsecret
- name: Run lldap with mysql and healthcheck again
@@ -422,9 +436,9 @@ jobs:
sleep 10s
bin/lldap healthcheck
env:
LLDAP_database_url: mysql://lldapuser:lldappass@localhost:3307/lldap
LLDAP_ldap_port: 3893
LLDAP_http_port: 17173
LLDAP_DATABASE_URL: mysql://lldapuser:lldappass@localhost:3307/lldap
LLDAP_LDAP_PORT: 3893
LLDAP_HTTP_PORT: 17173
LLDAP_JWT_SECRET: somejwtsecret
- name: Test Dummy User Postgres
@@ -738,5 +752,9 @@ jobs:
artifacts: aarch64-lldap.tar.gz,
amd64-lldap.tar.gz,
armhf-lldap.tar.gz
draft: true
omitBodyDuringUpdate: true
omitDraftDuringUpdate: true
omitNameDuringUpdate: true
env:
GITHUB_TOKEN: ${{ github.token }}

4
Cargo.lock generated
View File

@@ -2499,7 +2499,7 @@ checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89"
[[package]]
name = "lldap"
version = "0.6.1"
version = "0.6.2-alpha"
dependencies = [
"actix",
"actix-files",
@@ -2575,7 +2575,7 @@ dependencies = [
[[package]]
name = "lldap_app"
version = "0.6.1"
version = "0.6.2-alpha"
dependencies = [
"anyhow",
"base64 0.13.1",

View File

@@ -156,6 +156,7 @@ services:
- LLDAP_JWT_SECRET=REPLACE_WITH_RANDOM
- LLDAP_KEY_SEED=REPLACE_WITH_RANDOM
- LLDAP_LDAP_BASE_DN=dc=example,dc=com
- LLDAP_LDAP_USER_PASS=adminPas$word
# If using LDAPS, set enabled true and configure cert and key path
# - LLDAP_LDAPS_OPTIONS__ENABLED=true
# - LLDAP_LDAPS_OPTIONS__CERT_FILE=/path/to/certfile.crt
@@ -198,32 +199,36 @@ Each package offers a [systemd service](https://wiki.archlinux.org/title/systemd
When using the distributed packages, the default login is `admin/password`. You can change that from the web UI after starting the service.
<details>
<summary><b>Arch</b></summary>
<summary><b>Arch Linux</b></summary>
<br>
Arch Linux offers unofficial support through the <a href="https://wiki.archlinux.org/title/Arch_User_Repository">Arch User Repository (AUR)</a>.<br>
The package descriptions can be used <a href="https://wiki.archlinux.org/title/Arch_User_Repository#Getting_started">to create and install packages</a>.<br><br>
Maintainer: <a href="https://github.com/Zepmann">@Zepmann</a><br>
Support: <a href="https://github.com/lldap/lldap/discussions">Discussions</a><br>
Package repository: <a href="https://aur.archlinux.org/packages">Arch user repository</a><br>
Support: <a href="https://github.com/lldap/lldap/discussions/1044">Discussions</a><br>
Package repository: <a href="https://aur.archlinux.org/packages">Arch User Repository</a><br><br>
<table>
<tr>
<td>Available packages:</td>
<td>Package name</td>
<td>Maintainer</td>
<td>Description</td>
</tr>
<tr>
<td><a href="https://aur.archlinux.org/packages/lldap">lldap</a></td>
<td><a href="https://github.com/Zepmann">@Zepmann</a></td>
<td>Builds the latest stable version.</td>
</tr>
<tr>
<td></td>
<td><a href="https://aur.archlinux.org/packages/lldap-bin">lldap-bin</a></td>
<td>Uses the latest pre-compiled binaries from the <a href="https://aur.archlinux.org/packages/lldap-bin">releases in this repository</a>.<br>
This package is recommended if you want to run lldap on a system with limited resources.</td>
<td><a href="https://github.com/Zepmann">@Zepmann</a></td>
<td>Uses the latest pre-compiled binaries from the <a href="https://github.com/lldap/lldap/releases">releases in this repository</a>.<br>
This package is recommended if you want to run LLDAP on a system with limited resources.</td>
</tr>
<tr>
<td></td>
<td><a href="https://aur.archlinux.org/packages/lldap-git">lldap-git</a></td>
<td></td>
<td>Builds the latest main branch code.</td>
</tr>
</table>
LLDPA configuration file: /etc/lldap.toml<br>
LLDAP configuration file: /etc/lldap.toml<br>
</details>
<details>
<summary><b>Debian</b></summary>
@@ -587,6 +592,7 @@ folder for help with:
- [Grafana](example_configs/grafana_ldap_config.toml)
- [Grocy](example_configs/grocy.md)
- [Harbor](example_configs/harbor.md)
- [HashiCorp Vault](example_configs/hashicorp-vault.md)
- [Hedgedoc](example_configs/hedgedoc.md)
- [Home Assistant](example_configs/home-assistant.md)
- [Jellyfin](example_configs/jellyfin.md)
@@ -594,6 +600,7 @@ folder for help with:
- [Jitsi Meet](example_configs/jitsi_meet.conf)
- [Kasm](example_configs/kasm.md)
- [KeyCloak](example_configs/keycloak.md)
- [Kimai](example_configs/kimai.yaml)
- [LibreNMS](example_configs/librenms.md)
- [Maddy](example_configs/maddy.md)
- [Mastodon](example_configs/mastodon.env.example)
@@ -707,6 +714,9 @@ modern identity protocols, check out Kanidm.
If you just set up the server, can get to the login page but the password you
set isn't working, try the following:
- If you have changed the admin password in the config after the first run, it
won't be used (unless you force its use with `force_ldap_user_pass_reset`).
The config password is only for the initial admin creation.
- (For docker): Make sure that the `/data` folder is persistent, either to a
docker volume or mounted from the host filesystem.
- Check if there is a `lldap_config.toml` file (either in `/data` for docker

View File

@@ -6,7 +6,7 @@ homepage = "https://github.com/lldap/lldap"
license = "GPL-3.0-only"
name = "lldap_app"
repository = "https://github.com/lldap/lldap"
version = "0.6.1"
version = "0.6.2-alpha"
include = ["src/**/*", "queries/**/*", "Cargo.toml", "../schema.graphql"]
[dependencies]

View File

@@ -0,0 +1,77 @@
# Configuration for HashiCorp Vault
Official LDAP configuration documentation is located [here](https://developer.hashicorp.com/vault/docs/auth/ldap).
**You'll need to authenticate using your root token or as a user who has permission to modify authentication methods!**
## User Interface
1. Navigate to `Access -> Authentication Methods`
2. Click `Enable new method +` in the top right and choose `LDAP` under `Infra`
3. Name the path whatever you want (preferably keep it default) and click `Enable method` at the bottom
* URL: `ldap://lldap.example.com:3890` or `ldaps://lldap.example.com:6360`
* LDAP Options
* If you're using LDAPS and your server does not have your LDAPS certificate installed check `Insecure TLS` otherwise leave this unchecked
* User Attribute: `uid`
* User Principal (UPN) Domain: **LEAVE THIS BLANK**
* Customize User Search
* Name of Object to bind (binddn): `cn=admin,ou=people,dc=example,dc=com`
* User DN: `ou=people,dc=example,dc=com`
* Bindpass: `ChangeMe!`
* User Search Filter: `(&(uid={{.Username}})(objectClass=person))`
* Customize Group Member Search
* Group Filter: `(&(member={{.UserDN}})(objectclass=groupOfUniqueNames))`
* Group Attribute: `cn`
* Group DN: `ou=groups,dc=example,dc=com`
4. Click `Save` at the bottom
5. Click into the auth menthod and then `Create group +` under the `Groups` tab
6. Set the name as the group you want users to have to authenticate to HashiCorp Vault
7. Set policy as `default` or whatever policy you want to tie to this group
8. Click `Save` at the bottom
As long as your user is in the group you specified, you should now be able to select `LDAP` from the dropdown on the login page and use your credentials.
## CLI
**This requires the vault CLI to be installed on your machine**
1. Set VAULT_ADDR environment variable
```bash
export VAULT_ADDR=https://vault.example.com
```
2. Login to vault and provide token when prompted
```bash
vault login
````
3. Enable the LDAP authentication method
```bash
vault auth enable ldap
```
4. Configure the LDAP authentication method
```bash
vault write auth/ldap/config \
url="ldaps://lldaps.example.com:6360" \
binddn="cn=admin,ou=people,dc=example,dc=com" \
bindpass="ChangeMe!" \
userdn="ou=people,dc=example,dc=com" \
userfilter="(&(uid={{.Username}})(objectClass=person))" \
groupdn="ou=groups,dc=example,dc=com" \
groupfilter="(&(member={{.UserDN}})(objectclass=groupOfUniqueNames))" \
userattr="uid" \
groupattr="cn" \
discoverdn=false
```
If you are using plain LDAP, change the URL accordingly. If you're using LDAPS and your server does not have your LDAPS certificate installed append `insecure_tls=true` to the bottom of the command.
5. Add your group to the LDAP configuration and set the policy
```bash
vault write auth/ldap/groups/vault_users policies=default
```
As long as your user is in the group you specified, you should now be able to select `LDAP` from the dropdown on the login page and use your credentials.

View File

@@ -0,0 +1,36 @@
# See https://www.kimai.org/documentation/local-yaml.html
# this file should be renamed local.yaml
kimai:
ldap:
activate: true
connection:
host: lldap
port: 3890 # 6360 for LDAPS
useSsl: false # true for LDAPS
useStartTls: false
username: uid=admin,ou=people,dc=example,dc=com
password: <PASSWORD_HERE>
accountFilterFormat: (&(objectClass=person)(uid=%s))
bindRequiresDn: true
optReferrals: false
user:
baseDn: ou=people, dc=example, dc=com
usernameAttribute: uid
filter: (&(objectClass=person)) # to filter by group, add (memberof=cn=kimai,ou=groups,dc=example,dc=com) [group 'kimai' must be created in web UI]
attributes:
- { ldap_attr: "uid", user_method: setUserIdentifier }
- { ldap_attr: "mail", user_method: setEmail }
- { ldap_attr: "cn", user_method: setAlias }
role:
baseDn: ou=groups, dc=example, dc=com
filter: (&(objectClass=groupOfUniqueNames))
usernameAttribute: cn
nameAttribute: cn
userDnAttribute: member
# Convert LDAP group name (nameAttribute) to Kimai role. Available roles are listed here: https://www.kimai.org/documentation/permissions.html
groups:
- { ldap_value: lldap_admin, role: ROLE_SUPER_ADMIN }
# add additional group mappings here

View File

@@ -1,18 +1,18 @@
# Configuration for OneDev
In Onedev, go to `Administration > Authentication Sources` and click `External Authentication`
Select `Generic LDAP`
In Onedev, go to `Administration > External Authentication Source > Authenticator` and Select `Generic LDAP`
* LDAP URL: ldap://lldap_ip_or_hostname:3890 or ldaps://lldap_ip_or_hostname:6360
* Authentication Required: On
* Manager DN: `uid=admin,ou=people,dc=example,dc=com`
* Manager Password: Your bind user's password
* User Search Base: `ou=people,dc=example,dc=com`
* User Search Filter: `(&(uid={0})(objectclass=person))`
* User Full Name Attribute: `displayName`
* Email Attribute: mail
* User SSH Key Attribute: (Leave Blank)
* Group Retrieval: "Search Groups Using Filter"
* Group Search Base: `ou=groups,dc=example,dc=com`
* Group Search Filter" `(&(uniqueMember={0})(objectclass=groupOfUniqueNames))`
* Group Search Filter: `(&(uniqueMember={0})(objectclass=groupOfUniqueNames))`
* Group Name Attribute: cn
* Create User As Guest: Off
* Default Group: "No Default Group"

View File

@@ -8,7 +8,7 @@ keywords = ["cli", "ldap", "graphql", "server", "authentication"]
license = "GPL-3.0-only"
name = "lldap"
repository = "https://github.com/lldap/lldap"
version = "0.6.1"
version = "0.6.2-alpha"
[dependencies]
actix = "0.13"

View File

@@ -314,8 +314,8 @@ pub struct UserRestrictedListerBackendHandler<'a, Handler> {
}
#[async_trait]
impl<'a, Handler: ReadSchemaBackendHandler + Sync> ReadSchemaBackendHandler
for UserRestrictedListerBackendHandler<'a, Handler>
impl<Handler: ReadSchemaBackendHandler + Sync> ReadSchemaBackendHandler
for UserRestrictedListerBackendHandler<'_, Handler>
{
async fn get_schema(&self) -> Result<Schema> {
let mut schema = self.handler.get_schema().await?;
@@ -331,8 +331,8 @@ impl<'a, Handler: ReadSchemaBackendHandler + Sync> ReadSchemaBackendHandler
}
#[async_trait]
impl<'a, Handler: UserListerBackendHandler + Sync> UserListerBackendHandler
for UserRestrictedListerBackendHandler<'a, Handler>
impl<Handler: UserListerBackendHandler + Sync> UserListerBackendHandler
for UserRestrictedListerBackendHandler<'_, Handler>
{
async fn list_users(
&self,
@@ -354,8 +354,8 @@ impl<'a, Handler: UserListerBackendHandler + Sync> UserListerBackendHandler
}
#[async_trait]
impl<'a, Handler: GroupListerBackendHandler + Sync> GroupListerBackendHandler
for UserRestrictedListerBackendHandler<'a, Handler>
impl<Handler: GroupListerBackendHandler + Sync> GroupListerBackendHandler
for UserRestrictedListerBackendHandler<'_, Handler>
{
async fn list_groups(&self, filters: Option<GroupRequestFilter>) -> Result<Vec<Group>> {
let group_filter = self
@@ -379,7 +379,7 @@ pub trait UserAndGroupListerBackendHandler:
}
#[async_trait]
impl<'a, Handler: GroupListerBackendHandler + UserListerBackendHandler + Sync>
UserAndGroupListerBackendHandler for UserRestrictedListerBackendHandler<'a, Handler>
impl<Handler: GroupListerBackendHandler + UserListerBackendHandler + Sync>
UserAndGroupListerBackendHandler for UserRestrictedListerBackendHandler<'_, Handler>
{
}

View File

@@ -37,7 +37,7 @@ impl<'de> Deserialize<'de> for TrueFalseAlways {
struct Visitor;
impl<'de> serde::de::Visitor<'de> for Visitor {
impl serde::de::Visitor<'_> for Visitor {
type Value = TrueFalseAlways;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {

View File

@@ -97,16 +97,16 @@ pub struct Configuration {
pub http_host: String,
#[builder(default = "17170")]
pub http_port: u16,
#[builder(default = r#"SecUtf8::from("secretjwtsecret")"#)]
pub jwt_secret: SecUtf8,
#[builder(default)]
pub jwt_secret: Option<SecUtf8>,
#[builder(default = r#"String::from("dc=example,dc=com")"#)]
pub ldap_base_dn: String,
#[builder(default = r#"UserId::new("admin")"#)]
pub ldap_user_dn: UserId,
#[builder(default)]
pub ldap_user_email: String,
#[builder(default = r#"SecUtf8::from("password")"#)]
pub ldap_user_pass: SecUtf8,
#[builder(default)]
pub ldap_user_pass: Option<SecUtf8>,
#[builder(default)]
pub force_ldap_user_pass_reset: TrueFalseAlways,
#[builder(default = "false")]
@@ -607,11 +607,24 @@ where
.unwrap_or_default(),
figment_config,
)?);
if config.jwt_secret == SecUtf8::from("secretjwtsecret") {
println!("WARNING: Default JWT secret used! This is highly unsafe and can allow attackers to log in as admin.");
}
if config.ldap_user_pass == SecUtf8::from("password") {
println!("WARNING: Unsecure default admin password is used.");
if config.jwt_secret.is_none() {
use rand::{seq::SliceRandom, Rng};
struct Symbols;
impl rand::prelude::Distribution<char> for Symbols {
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> char {
*b"01234567890ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+,-./:;<=>?_~!@#$%^&*()[]{}:;".choose(rng).unwrap() as char
}
}
bail!("The JWT secret must be initialized to a random string, preferably at least 32 characters long. \
Either set the `jwt_secret` config value or the `LLDAP_JWT_SECRET` environment variable. \
You can generate the value by running\n\
LC_ALL=C tr -dc 'A-Za-z0-9!#%&'\\''()*+,-./:;<=>?@[\\]^_{{|}}~' </dev/urandom | head -c 32; echo ''\n\
or you can use this random value: {}",
rand::thread_rng()
.sample_iter(&Symbols)
.take(32)
.collect::<String>());
}
if config.smtp_options.tls_required.is_some() {
println!("DEPRECATED: smtp_options.tls_required field is deprecated, it never did anything. You can replace it with smtp_options.smtp_encryption.");
@@ -669,7 +682,9 @@ mod tests {
fn figment_location_extraction_key_file() {
Jail::expect_with(|jail| {
jail.create_file("lldap_config.toml", r#"key_file = "test""#)?;
jail.clear_env();
jail.set_env("LLDAP_KEY_SEED", "a123");
jail.set_env("LLDAP_JWT_SECRET", "secret");
let ignore_keys = ["key_file", "cert_file"];
let figment_config = Figment::from(Serialized::defaults(
ConfigurationBuilder::default().private_build().unwrap(),
@@ -696,7 +711,9 @@ mod tests {
fn check_server_setup_key_extraction_seed_success_with_nonexistant_file() {
Jail::expect_with(|jail| {
jail.create_file("lldap_config.toml", r#"key_file = "test""#)?;
jail.clear_env();
jail.set_env("LLDAP_KEY_SEED", "a123");
jail.set_env("LLDAP_JWT_SECRET", "secret");
init(default_run_opts()).unwrap();
Ok(())
});
@@ -706,7 +723,9 @@ mod tests {
fn check_server_setup_key_extraction_seed_failure_with_existing_file() {
Jail::expect_with(|jail| {
jail.create_file("lldap_config.toml", r#"key_file = "test""#)?;
jail.clear_env();
jail.set_env("LLDAP_KEY_SEED", "a123");
jail.set_env("LLDAP_JWT_SECRET", "secret");
write_random_key(jail, "test");
init(default_run_opts()).unwrap_err();
Ok(())
@@ -717,6 +736,8 @@ mod tests {
fn check_server_setup_key_extraction_file_success_with_existing_file() {
Jail::expect_with(|jail| {
jail.create_file("lldap_config.toml", r#"key_file = "test""#)?;
jail.clear_env();
jail.set_env("LLDAP_JWT_SECRET", "secret");
write_random_key(jail, "test");
init(default_run_opts()).unwrap();
Ok(())
@@ -727,6 +748,8 @@ mod tests {
fn check_server_setup_key_extraction_file_success_with_nonexistent_file() {
Jail::expect_with(|jail| {
jail.create_file("lldap_config.toml", r#"key_file = "test""#)?;
jail.clear_env();
jail.set_env("LLDAP_JWT_SECRET", "secret");
init(default_run_opts()).unwrap();
Ok(())
});
@@ -736,6 +759,8 @@ mod tests {
fn check_server_setup_key_extraction_file_with_previous_different_file() {
Jail::expect_with(|jail| {
jail.create_file("lldap_config.toml", r#"key_file = "test""#)?;
jail.clear_env();
jail.set_env("LLDAP_JWT_SECRET", "secret");
write_random_key(jail, "test");
let config = init(default_run_opts()).unwrap();
let info = config.get_private_key_info();
@@ -766,6 +791,8 @@ mod tests {
#[test]
fn check_server_setup_key_extraction_file_to_seed() {
Jail::expect_with(|jail| {
jail.clear_env();
jail.set_env("LLDAP_JWT_SECRET", "secret");
jail.create_file("lldap_config.toml", "")?;
write_random_key(jail, "server_key");
init(default_run_opts()).unwrap();
@@ -782,6 +809,8 @@ mod tests {
#[test]
fn check_server_setup_key_extraction_file_to_seed_removed_file() {
Jail::expect_with(|jail| {
jail.clear_env();
jail.set_env("LLDAP_JWT_SECRET", "secret");
jail.create_file("lldap_config.toml", "")?;
write_random_key(jail, "server_key");
let config = init(default_run_opts()).unwrap();

View File

@@ -189,7 +189,7 @@ pub async fn build_tcp_server<Backend>(
where
Backend: TcpBackendHandler + BackendHandler + LoginHandler + OpaqueHandler + Clone + 'static,
{
let jwt_secret = config.jwt_secret.clone();
let jwt_secret = config.jwt_secret.clone().unwrap();
let jwt_blacklist = backend_handler
.get_jwt_blacklist()
.await

View File

@@ -33,8 +33,17 @@ use tracing::{debug, error, info, instrument, span, warn, Instrument, Level};
mod domain;
mod infra;
const ADMIN_PASSWORD_MISSING_ERROR : &str = "The LDAP admin password must be initialized. \
Either set the `ldap_user_pass` config value or the `LLDAP_LDAP_USER_PASS` environment variable. \
A minimum of 8 characters is recommended.";
async fn create_admin_user(handler: &SqlBackendHandler, config: &Configuration) -> Result<()> {
let pass_length = config.ldap_user_pass.unsecure().len();
let pass_length = config
.ldap_user_pass
.as_ref()
.expect(ADMIN_PASSWORD_MISSING_ERROR)
.unsecure()
.len();
assert!(
pass_length >= 8,
"Minimum password length is 8 characters, got {} characters",
@@ -48,7 +57,11 @@ async fn create_admin_user(handler: &SqlBackendHandler, config: &Configuration)
..Default::default()
})
.and_then(|_| {
register_password(handler, config.ldap_user_dn.clone(), &config.ldap_user_pass)
register_password(
handler,
config.ldap_user_dn.clone(),
config.ldap_user_pass.as_ref().unwrap(),
)
})
.await
.context("Error creating admin user")?;
@@ -161,7 +174,10 @@ async fn set_up_server(config: Configuration) -> Result<ServerBuilder> {
register_password(
&backend_handler,
config.ldap_user_dn.clone(),
&config.ldap_user_pass,
config
.ldap_user_pass
.as_ref()
.expect(ADMIN_PASSWORD_MISSING_ERROR),
)
.instrument(span)
.await

View File

@@ -3,6 +3,8 @@ use std::env::var;
pub const DB_KEY: &str = "LLDAP_DATABASE_URL";
pub const PRIVATE_KEY_SEED: &str = "LLDAP_KEY_SEED";
pub const JWT_SECRET: &str = "LLDAP_JWT_SECRET";
pub const LDAP_USER_PASSWORD: &str = "LLDAP_LDAP_USER_PASS";
pub fn database_url() -> String {
let url = var(DB_KEY).ok();

View File

@@ -43,14 +43,13 @@ const MAX_HEALTHCHECK_ATTEMPS: u8 = 10;
impl LLDAPFixture {
pub fn new() -> Self {
let mut cmd = create_lldap_command();
cmd.arg("run");
cmd.arg("--verbose");
let child = cmd.spawn().expect("Unable to start server");
let child = create_lldap_command("run")
.arg("--verbose")
.spawn()
.expect("Unable to start server");
let mut started = false;
for _ in 0..MAX_HEALTHCHECK_ATTEMPS {
let status = create_lldap_command()
.arg("healthcheck")
let status = create_lldap_command("healthcheck")
.status()
.expect("healthcheck fail");
if status.success() {
@@ -229,7 +228,7 @@ pub fn new_id(prefix: Option<&str>) -> String {
}
}
fn create_lldap_command() -> Command {
fn create_lldap_command(subcommand: &str) -> Command {
let mut cmd = Command::cargo_bin(env!("CARGO_PKG_NAME")).expect("cargo bin not found");
// This gives us the absolute path of the repo base instead of running it in server/
let path = canonicalize("..").expect("canonical path");
@@ -237,5 +236,10 @@ fn create_lldap_command() -> Command {
cmd.current_dir(path);
cmd.env(env::DB_KEY, db_url);
cmd.env(env::PRIVATE_KEY_SEED, "Random value");
cmd.env(env::JWT_SECRET, "Random value");
cmd.env(env::LDAP_USER_PASSWORD, "password");
cmd.arg(subcommand);
cmd.arg("--config-file=/dev/null");
cmd.arg("--server-key-file=''");
cmd
}