mirror of
https://github.com/ViViDboarder/bitwarden_rs_ldap.git
synced 2024-11-16 00:06:27 +00:00
Compare commits
No commits in common. "master" and "v0.6.0" have entirely different histories.
22
.github/dependabot.yml
vendored
22
.github/dependabot.yml
vendored
@ -1,22 +0,0 @@
|
|||||||
# Docs: <https://docs.github.com/en/free-pro-team@latest/github/administering-a-repository/customizing-dependency-updates>
|
|
||||||
|
|
||||||
version: 2
|
|
||||||
|
|
||||||
updates:
|
|
||||||
- package-ecosystem: github-actions
|
|
||||||
directory: /
|
|
||||||
schedule: {interval: monthly}
|
|
||||||
reviewers: [ViViDboarder]
|
|
||||||
assignees: [ViViDboarder]
|
|
||||||
|
|
||||||
- package-ecosystem: docker
|
|
||||||
directory: /
|
|
||||||
schedule: {interval: monthly}
|
|
||||||
reviewers: [ViViDboarder]
|
|
||||||
assignees: [ViViDboarder]
|
|
||||||
|
|
||||||
- package-ecosystem: cargo
|
|
||||||
directory: /
|
|
||||||
schedule: {interval: monthly}
|
|
||||||
reviewers: [ViViDboarder]
|
|
||||||
assignees: [ViViDboarder]
|
|
13
.github/workflows/cargo.yml
vendored
13
.github/workflows/cargo.yml
vendored
@ -16,20 +16,13 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v2
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
run: cargo build --verbose
|
run: cargo build --verbose
|
||||||
|
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
run: cargo test --verbose
|
run: cargo test --verbose
|
||||||
|
|
||||||
- uses: actions/setup-python@v5
|
- uses: actions/setup-python@v2
|
||||||
|
|
||||||
- name: Run pre-commit hooks
|
- name: Run pre-commit hooks
|
||||||
uses: pre-commit/action@v3.0.1
|
uses: pre-commit/action@v2.0.2
|
||||||
env:
|
|
||||||
SKIP: hadolint
|
|
||||||
|
|
||||||
- name: Run hadolint
|
|
||||||
uses: hadolint/hadolint-action@v3.1.0
|
|
||||||
|
11
.github/workflows/docker.yml
vendored
11
.github/workflows/docker.yml
vendored
@ -19,13 +19,16 @@ jobs:
|
|||||||
- dockerfile: Dockerfile
|
- dockerfile: Dockerfile
|
||||||
latest: "auto"
|
latest: "auto"
|
||||||
suffix: ""
|
suffix: ""
|
||||||
|
- dockerfile: Dockerfile.alpine
|
||||||
|
latest: "false"
|
||||||
|
suffix: "-alpine"
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v2
|
||||||
- name: Docker meta
|
- name: Docker meta
|
||||||
id: meta
|
id: meta
|
||||||
uses: docker/metadata-action@v5
|
uses: docker/metadata-action@v3
|
||||||
with:
|
with:
|
||||||
images: vividboarder/vaultwarden_ldap
|
images: vividboarder/vaultwarden_ldap
|
||||||
flavor: |
|
flavor: |
|
||||||
@ -39,12 +42,12 @@ jobs:
|
|||||||
|
|
||||||
- name: Login to DockerHub
|
- name: Login to DockerHub
|
||||||
if: github.event_name != 'pull_request'
|
if: github.event_name != 'pull_request'
|
||||||
uses: docker/login-action@v3
|
uses: docker/login-action@v1
|
||||||
with:
|
with:
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
- name: Build and push
|
- name: Build and push
|
||||||
uses: docker/build-push-action@v6
|
uses: docker/build-push-action@v2
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
file: ${{ matrix.dockerfile }}
|
file: ${{ matrix.dockerfile }}
|
||||||
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -6,4 +6,4 @@
|
|||||||
**/*.rs.bk
|
**/*.rs.bk
|
||||||
|
|
||||||
# Ignore config while developing
|
# Ignore config while developing
|
||||||
./config.toml
|
config.toml
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
---
|
---
|
||||||
repos:
|
repos:
|
||||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||||
rev: v4.6.0
|
rev: v3.4.0
|
||||||
hooks:
|
hooks:
|
||||||
- id: check-added-large-files
|
- id: check-added-large-files
|
||||||
- id: check-yaml
|
- id: check-yaml
|
||||||
@ -16,10 +16,7 @@ repos:
|
|||||||
- id: cargo-check
|
- id: cargo-check
|
||||||
- id: clippy
|
- id: clippy
|
||||||
- repo: https://github.com/IamTheFij/docker-pre-commit
|
- repo: https://github.com/IamTheFij/docker-pre-commit
|
||||||
rev: v3.0.1
|
rev: v2.0.0
|
||||||
hooks:
|
hooks:
|
||||||
- id: docker-compose-check
|
- id: docker-compose-check
|
||||||
- repo: https://github.com/hadolint/hadolint
|
|
||||||
rev: v2.12.0
|
|
||||||
hooks:
|
|
||||||
- id: hadolint
|
- id: hadolint
|
||||||
|
2157
Cargo.lock
generated
2157
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
10
Cargo.toml
10
Cargo.toml
@ -1,17 +1,15 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "vaultwarden_ldap"
|
name = "vaultwarden_ldap"
|
||||||
version = "2.0.2"
|
version = "0.6.0"
|
||||||
authors = ["ViViDboarder <vividboarder@gmail.com>"]
|
authors = ["ViViDboarder <vividboarder@gmail.com>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
ldap3 = "0.11"
|
ldap3 = "0.6"
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
toml = "0.8"
|
toml = "0.5"
|
||||||
reqwest = { version = "0.12", features = ["json", "blocking"] }
|
reqwest = "0.9"
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
thiserror = "1.0"
|
thiserror = "1.0"
|
||||||
anyhow = "1.0"
|
anyhow = "1.0"
|
||||||
envy = "0.4.1"
|
envy = "0.4.1"
|
||||||
pledge = "0.4.2"
|
|
||||||
unveil = "0.3.2"
|
|
||||||
|
13
Dockerfile
13
Dockerfile
@ -1,4 +1,7 @@
|
|||||||
FROM rust:1.82 as builder
|
ARG BUILD_TAG=1.46
|
||||||
|
ARG RUN_TAG=$BUILD_TAG
|
||||||
|
|
||||||
|
FROM rust:$BUILD_TAG as builder
|
||||||
|
|
||||||
WORKDIR /usr/src/
|
WORKDIR /usr/src/
|
||||||
RUN USER=root cargo new --bin vaultwarden_ldap
|
RUN USER=root cargo new --bin vaultwarden_ldap
|
||||||
@ -9,17 +12,13 @@ COPY Cargo.toml Cargo.lock ./
|
|||||||
RUN cargo build --locked --release
|
RUN cargo build --locked --release
|
||||||
|
|
||||||
# Remove bins to make sure we rebuild
|
# Remove bins to make sure we rebuild
|
||||||
# hadolint ignore=DL3059
|
|
||||||
RUN rm ./target/release/deps/vaultwarden_ldap*
|
RUN rm ./target/release/deps/vaultwarden_ldap*
|
||||||
# Copy source and install
|
# Copy source and install
|
||||||
COPY src ./src
|
COPY src ./src
|
||||||
RUN cargo build --release
|
RUN cargo build --release
|
||||||
|
|
||||||
# Use most recent ubuntu LTS release
|
FROM rust:$RUN_TAG
|
||||||
FROM ubuntu:24.04
|
WORKDIR /app
|
||||||
RUN apt-get update \
|
|
||||||
&& apt-get install -y --no-install-recommends 'ca-certificates=20240203' 'libssl-dev=3.*' \
|
|
||||||
&& rm -rf /var/cache/apt/lists
|
|
||||||
COPY --from=builder /usr/src/vaultwarden_ldap/target/release/vaultwarden_ldap /usr/local/bin/
|
COPY --from=builder /usr/src/vaultwarden_ldap/target/release/vaultwarden_ldap /usr/local/bin/
|
||||||
|
|
||||||
CMD ["/usr/local/bin/vaultwarden_ldap"]
|
CMD ["/usr/local/bin/vaultwarden_ldap"]
|
||||||
|
21
Dockerfile.alpine
Normal file
21
Dockerfile.alpine
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
FROM ekidd/rust-musl-builder:1.46.0 AS builder
|
||||||
|
|
||||||
|
WORKDIR /home/rust/src
|
||||||
|
|
||||||
|
# Cache build deps
|
||||||
|
RUN USER=rust cargo init
|
||||||
|
COPY Cargo.toml Cargo.lock ./
|
||||||
|
RUN cargo build --locked --release && \
|
||||||
|
rm src/*.rs
|
||||||
|
|
||||||
|
COPY --chown=rust:rust ./src ./src
|
||||||
|
RUN touch ./src/main.rs && \
|
||||||
|
cargo build --release
|
||||||
|
|
||||||
|
FROM alpine:3
|
||||||
|
RUN apk --no-cache add ca-certificates=20191127-r5
|
||||||
|
COPY --from=builder \
|
||||||
|
/home/rust/src/target/x86_64-unknown-linux-musl/release/vaultwarden_ldap \
|
||||||
|
/usr/local/bin/
|
||||||
|
|
||||||
|
CMD ["/usr/local/bin/vaultwarden_ldap"]
|
43
Makefile
43
Makefile
@ -34,45 +34,22 @@ test:
|
|||||||
cargo test
|
cargo test
|
||||||
|
|
||||||
# Run bootstrapped integration test
|
# Run bootstrapped integration test
|
||||||
.PHONY: itest-up
|
|
||||||
itest-up:
|
|
||||||
docker compose -f docker-compose.yml \
|
|
||||||
-f itest/docker-compose.itest.yml \
|
|
||||||
build
|
|
||||||
docker compose -f docker-compose.yml \
|
|
||||||
-f itest/docker-compose.itest.yml \
|
|
||||||
up -d vaultwarden ldap
|
|
||||||
|
|
||||||
.PHONY: itest-run
|
|
||||||
itest-run:
|
|
||||||
docker compose -f docker-compose.yml \
|
|
||||||
-f itest/docker-compose.itest.yml \
|
|
||||||
run ldap_sync
|
|
||||||
|
|
||||||
.PHONY: itest-stop
|
|
||||||
itest-stop:
|
|
||||||
docker compose stop
|
|
||||||
|
|
||||||
.PHONY: itest
|
.PHONY: itest
|
||||||
itest: itest-up itest-run itest-stop
|
itest:
|
||||||
|
docker-compose -f docker-compose.yml \
|
||||||
|
-f itest/docker-compose.itest.yml \
|
||||||
|
up --build
|
||||||
|
|
||||||
# Run bootstrapped integration test using env for config
|
# Run bootstrapped integration test using env for config
|
||||||
.PHONY: itest-env
|
.PHONY: itest-env
|
||||||
itest-env:
|
itest-env:
|
||||||
docker compose -f docker-compose.yml \
|
docker-compose -f docker-compose.yml \
|
||||||
-f itest/docker-compose.itest-env.yml \
|
-f itest/docker-compose.itest-env.yml \
|
||||||
build
|
up --build
|
||||||
docker compose -f docker-compose.yml \
|
|
||||||
-f itest/docker-compose.itest-env.yml \
|
|
||||||
up -d vaultwarden ldap
|
|
||||||
docker compose -f docker-compose.yml \
|
|
||||||
-f itest/docker-compose.itest-env.yml \
|
|
||||||
run ldap_sync
|
|
||||||
docker compose stop
|
|
||||||
|
|
||||||
.PHONY: clean-itest
|
.PHONY: clean-itest
|
||||||
clean-itest:
|
clean-itest:
|
||||||
docker compose down -v
|
docker-compose down -v
|
||||||
|
|
||||||
# Installs pre-commit hooks
|
# Installs pre-commit hooks
|
||||||
.PHONY: install-hooks
|
.PHONY: install-hooks
|
||||||
@ -94,8 +71,12 @@ clean:
|
|||||||
rm -f ./target
|
rm -f ./target
|
||||||
|
|
||||||
.PHONY: docker-build-all
|
.PHONY: docker-build-all
|
||||||
docker-build-all: docker-build
|
docker-build-all: docker-build docker-build-alpine
|
||||||
|
|
||||||
.PHONY: docker-build
|
.PHONY: docker-build
|
||||||
docker-build:
|
docker-build:
|
||||||
docker build -f ./Dockerfile -t $(DOCKER_TAG) .
|
docker build -f ./Dockerfile -t $(DOCKER_TAG) .
|
||||||
|
|
||||||
|
.PHONY: docker-build-alpine
|
||||||
|
docker-build-alpine:
|
||||||
|
docker build -f ./Dockerfile.alpine -t $(DOCKER_TAG):alpine .
|
||||||
|
24
README.md
24
README.md
@ -1,7 +1,7 @@
|
|||||||
# vaultwarden_ldap
|
# vaultwarden_ldap
|
||||||
LDAP user invites for [vaultwarden](https://github.com/dani-garcia/vaultwarden)
|
An LDAP connector for [vaultwarden](https://github.com/dani-garcia/vaultwarden)
|
||||||
|
|
||||||
After configuring, run `vaultwarden_ldap` and it will invite any users it finds in LDAP to your `vaultwarden` instance. This is NOT a sync tool like the [Bitwarden Directory Connector](https://bitwarden.com/help/directory-sync/).
|
After configuring, run `vaultwarden_ldap` and it will invite any users it finds in LDAP to your `vaultwarden` instance.
|
||||||
|
|
||||||
## Deploying
|
## Deploying
|
||||||
|
|
||||||
@ -34,8 +34,6 @@ Configuration values are as follows:
|
|||||||
|`ldap_sync_interval_seconds`|Integer|Optional|Number of seconds to wait between each LDAP request. Defaults to `60`|
|
|`ldap_sync_interval_seconds`|Integer|Optional|Number of seconds to wait between each LDAP request. Defaults to `60`|
|
||||||
|`ldap_sync_loop`|Boolean|Optional|Indicates whether or not syncing should be polled in a loop or done once. Defaults to `true`|
|
|`ldap_sync_loop`|Boolean|Optional|Indicates whether or not syncing should be polled in a loop or done once. Defaults to `true`|
|
||||||
|
|
||||||
Alternatively, instead of using `config.toml`, all values can be provided using enviroment variables prefixed with `APP_`. For example: `APP_VAULTWARDEN_URL=https://vault.example.com`
|
|
||||||
|
|
||||||
## Development
|
## Development
|
||||||
|
|
||||||
This repo has a predefined set of [pre-commit](https://pre-commit.com) rules. You can install pre-commit via any means you'd like. Once your system has `pre-commit` installed, you can run `make install-hooks` to ensure the hooks will run with every commit. You can also force running all hooks with `make check`.
|
This repo has a predefined set of [pre-commit](https://pre-commit.com) rules. You can install pre-commit via any means you'd like. Once your system has `pre-commit` installed, you can run `make install-hooks` to ensure the hooks will run with every commit. You can also force running all hooks with `make check`.
|
||||||
@ -44,18 +42,7 @@ For those less familiar with `cargo`, you can use the `make` targets that have b
|
|||||||
|
|
||||||
## Testing
|
## Testing
|
||||||
|
|
||||||
There are no unit tests, but there are integration tests that require manual verification.
|
All testing is manual right now. First step is to set up Bitwarden and the LDAP server.
|
||||||
|
|
||||||
### Integration tests
|
|
||||||
|
|
||||||
Running `make itest` will spin up an ldap server with a test user, a Vaultwarden server, and then run the sync. If successful the log should show an invitation sent to the test user. If you run `make itest` again, it should show no invites sent because the user already has been invited. If you'd like to reset the testing, `make clean-itest` will clear out the Vaultwarden database and start fresh.
|
|
||||||
|
|
||||||
It's also possible to test passing configs via enviornment variables by running `make itest-env`. The validation steps are the same.
|
|
||||||
|
|
||||||
|
|
||||||
### Steps for manual testing
|
|
||||||
|
|
||||||
The first step is to set up Bitwarden and the LDAP server.
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker-compose up -d vaultwarden ldap ldap_admin
|
docker-compose up -d vaultwarden ldap ldap_admin
|
||||||
@ -85,3 +72,8 @@ docker-compose up ldap_sync
|
|||||||
Alternately, you can bootstrap some of this by running:
|
Alternately, you can bootstrap some of this by running:
|
||||||
|
|
||||||
docker-compose -f docker-compose.yml -f itest/docker-compose.itest.yml up --build
|
docker-compose -f docker-compose.yml -f itest/docker-compose.itest.yml up --build
|
||||||
|
|
||||||
|
## Future
|
||||||
|
|
||||||
|
* Any kind of proper logging
|
||||||
|
* Tests
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
---
|
---
|
||||||
|
version: '3'
|
||||||
services:
|
services:
|
||||||
ldap_sync:
|
ldap_sync:
|
||||||
build:
|
build:
|
||||||
@ -9,7 +10,7 @@ services:
|
|||||||
# ./root.cert:/usr/src/vaultwarden_ldap/root.cert:ro
|
# ./root.cert:/usr/src/vaultwarden_ldap/root.cert:ro
|
||||||
environment:
|
environment:
|
||||||
CONFIG_PATH: /config.toml
|
CONFIG_PATH: /config.toml
|
||||||
RUST_BACKTRACE: full
|
RUST_BACKTRACE: 1
|
||||||
depends_on:
|
depends_on:
|
||||||
- vaultwarden
|
- vaultwarden
|
||||||
- ldap
|
- ldap
|
||||||
@ -23,7 +24,6 @@ services:
|
|||||||
ADMIN_TOKEN: admin
|
ADMIN_TOKEN: admin
|
||||||
SIGNUPS_ALLOWED: 'false'
|
SIGNUPS_ALLOWED: 'false'
|
||||||
INVITATIONS_ALLOWED: 'true'
|
INVITATIONS_ALLOWED: 'true'
|
||||||
I_REALLY_WANT_VOLATILE_STORAGE: 'true'
|
|
||||||
|
|
||||||
ldap:
|
ldap:
|
||||||
image: osixia/openldap
|
image: osixia/openldap
|
||||||
|
@ -1,16 +1,22 @@
|
|||||||
|
# LDIF Export for cn=Users,dc=example,dc=org
|
||||||
|
# Server: ldap (ldap)
|
||||||
|
# Search Scope: sub
|
||||||
|
# Search Filter: (objectClass=*)
|
||||||
|
# Total Entries: 2
|
||||||
|
#
|
||||||
# Generated by phpLDAPadmin (http://phpldapadmin.sourceforge.net) on May 4, 2021 6:06 pm
|
# Generated by phpLDAPadmin (http://phpldapadmin.sourceforge.net) on May 4, 2021 6:06 pm
|
||||||
# Version: 1.2.5
|
# Version: 1.2.5
|
||||||
|
|
||||||
version: 1
|
version: 1
|
||||||
|
|
||||||
# Entry 1: Users group
|
# Entry 1: cn=Users,dc=example,dc=org
|
||||||
dn: cn=Users,dc=example,dc=org
|
dn: cn=Users,dc=example,dc=org
|
||||||
cn: Users
|
cn: Users
|
||||||
gidnumber: 500
|
gidnumber: 500
|
||||||
objectclass: posixGroup
|
objectclass: posixGroup
|
||||||
objectclass: top
|
objectclass: top
|
||||||
|
|
||||||
# Entry 2: User with email
|
# Entry 2: cn=Someone,cn=Users,dc=example,dc=org
|
||||||
dn: cn=Someone,cn=Users,dc=example,dc=org
|
dn: cn=Someone,cn=Users,dc=example,dc=org
|
||||||
cn: Someone
|
cn: Someone
|
||||||
gidnumber: 500
|
gidnumber: 500
|
||||||
@ -23,7 +29,7 @@ sn: Someone
|
|||||||
uid: someone
|
uid: someone
|
||||||
uidnumber: 1000
|
uidnumber: 1000
|
||||||
|
|
||||||
# Entry 3: User with no email
|
# Entry 3: cn=SomeoneNoEmail,cn=Users,dc=example,dc=org
|
||||||
dn: cn=SomeoneNoEmail,cn=Users,dc=example,dc=org
|
dn: cn=SomeoneNoEmail,cn=Users,dc=example,dc=org
|
||||||
cn: SomeoneNoEmail
|
cn: SomeoneNoEmail
|
||||||
gidnumber: 500
|
gidnumber: 500
|
||||||
@ -35,15 +41,13 @@ sn: SomeoneNoEmail
|
|||||||
uid: someonenoemail
|
uid: someonenoemail
|
||||||
uidnumber: 1001
|
uidnumber: 1001
|
||||||
|
|
||||||
# Entry 4: User with email containing +
|
# Entry 4: cn=SomeoneNoEmailNoUid,cn=Users,dc=example,dc=org
|
||||||
dn: cn=SomeonePlus,cn=Users,dc=example,dc=org
|
# dn: cn=SomeoneNoEmailNoUid,cn=Users,dc=example,dc=org
|
||||||
cn: SomeonePlus
|
# cn: SomeoneNoEmailNoUid
|
||||||
gidnumber: 500
|
# gidnumber: 500
|
||||||
homedirectory: /home/users/someoneplus
|
# homedirectory: /home/users/someonenoemailnoUid
|
||||||
mail: test+plus@example.com
|
# objectclass: inetOrgPerson
|
||||||
objectclass: inetOrgPerson
|
# objectclass: posixAccount
|
||||||
objectclass: posixAccount
|
# objectclass: top
|
||||||
objectclass: top
|
# sn: SomeoneNoEmail
|
||||||
sn: SomeonePlus
|
# uidnumber: 1002
|
||||||
uid: someoneplus
|
|
||||||
uidnumber: 1002
|
|
@ -1,8 +0,0 @@
|
|||||||
vaultwarden_url = "http://vaultwarden:80"
|
|
||||||
vaultwarden_admin_token = "admin"
|
|
||||||
ldap_host = "ldap"
|
|
||||||
ldap_bind_dn = "cn=readonly,dc=example,dc=org"
|
|
||||||
ldap_bind_password = "readonly"
|
|
||||||
ldap_search_base_dn = "dc=example,dc=org"
|
|
||||||
ldap_search_filter = "(&(objectClass=*)(uid=*))"
|
|
||||||
ldap_sync_loop = false
|
|
@ -1,4 +1,5 @@
|
|||||||
---
|
---
|
||||||
|
version: '3'
|
||||||
services:
|
services:
|
||||||
ldap_sync:
|
ldap_sync:
|
||||||
environment:
|
environment:
|
||||||
@ -10,11 +11,11 @@ services:
|
|||||||
APP_LDAP_BIND_PASSWORD: "admin"
|
APP_LDAP_BIND_PASSWORD: "admin"
|
||||||
APP_LDAP_SEARCH_BASE_DN: "dc=example,dc=org"
|
APP_LDAP_SEARCH_BASE_DN: "dc=example,dc=org"
|
||||||
APP_LDAP_SEARCH_FILTER: "(&(objectClass=*)(uid=*))"
|
APP_LDAP_SEARCH_FILTER: "(&(objectClass=*)(uid=*))"
|
||||||
APP_LDAP_SYNC_LOOP: "false"
|
APP_LDAP_SYNC_INTERVAL_SECONDS: 10
|
||||||
|
|
||||||
vaultwarden: {}
|
vaultwarden:
|
||||||
|
|
||||||
ldap:
|
ldap:
|
||||||
command: ["--copy-service"]
|
command: ["--copy-service"]
|
||||||
volumes:
|
volumes:
|
||||||
- ./itest/ldif:/container/service/slapd/assets/config/bootstrap/ldif/custom
|
- ./itest/50-seed-user.ldif:/container/service/slapd/assets/config/bootstrap/ldif/custom/50-seed-user.ldif
|
||||||
|
@ -1,12 +1,11 @@
|
|||||||
---
|
---
|
||||||
|
version: '3'
|
||||||
services:
|
services:
|
||||||
ldap_sync:
|
ldap_sync:
|
||||||
volumes:
|
|
||||||
- ./itest/config.toml:/config.toml:ro
|
|
||||||
|
|
||||||
vaultwarden: {}
|
vaultwarden:
|
||||||
|
|
||||||
ldap:
|
ldap:
|
||||||
command: ["--copy-service"]
|
command: ["--copy-service"]
|
||||||
volumes:
|
volumes:
|
||||||
- ./itest/ldif:/container/service/slapd/assets/config/bootstrap/ldif/custom
|
- ./itest/50-seed-user.ldif:/container/service/slapd/assets/config/bootstrap/ldif/custom/50-seed-user.ldif
|
||||||
|
@ -37,9 +37,9 @@ pub fn read_config_from_file() -> Result<Config, String> {
|
|||||||
let config_path = get_config_path();
|
let config_path = get_config_path();
|
||||||
|
|
||||||
let contents = fs::read_to_string(&config_path)
|
let contents = fs::read_to_string(&config_path)
|
||||||
.map_err(|err| format!("Failed to open config file at {}: {}", config_path, err))?;
|
.map_err(|_| format!("Failed to open config file at {}", config_path))?;
|
||||||
let config: Config = toml::from_str(contents.as_str())
|
let config: Config = toml::from_str(contents.as_str())
|
||||||
.map_err(|err| format!("Failed to parse config file at {}: {}", config_path, err))?;
|
.map_err(|_| format!("Failed to parse config file at {}", config_path))?;
|
||||||
|
|
||||||
println!("Config read from file at {}", config_path);
|
println!("Config read from file at {}", config_path);
|
||||||
Ok(config)
|
Ok(config)
|
||||||
|
24
src/main.rs
24
src/main.rs
@ -1,7 +1,5 @@
|
|||||||
extern crate anyhow;
|
extern crate anyhow;
|
||||||
extern crate ldap3;
|
extern crate ldap3;
|
||||||
extern crate pledge;
|
|
||||||
extern crate unveil;
|
|
||||||
|
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::thread::sleep;
|
use std::thread::sleep;
|
||||||
@ -11,8 +9,6 @@ use anyhow::Context as _;
|
|||||||
use anyhow::Error as AnyError;
|
use anyhow::Error as AnyError;
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use ldap3::{DerefAliases, LdapConn, LdapConnSettings, Scope, SearchEntry, SearchOptions};
|
use ldap3::{DerefAliases, LdapConn, LdapConnSettings, Scope, SearchEntry, SearchOptions};
|
||||||
use pledge::pledge;
|
|
||||||
use unveil::unveil;
|
|
||||||
|
|
||||||
mod config;
|
mod config;
|
||||||
mod vw_admin;
|
mod vw_admin;
|
||||||
@ -25,16 +21,6 @@ fn main() {
|
|||||||
config.get_vaultwarden_root_cert_file(),
|
config.get_vaultwarden_root_cert_file(),
|
||||||
);
|
);
|
||||||
|
|
||||||
unveil(config::get_config_path(), "r")
|
|
||||||
.or_else(unveil::Error::ignore_platform)
|
|
||||||
.expect("Could not unveil config file");
|
|
||||||
unveil("", "")
|
|
||||||
.or_else(unveil::Error::ignore_platform)
|
|
||||||
.expect("Could not disable further unveils");
|
|
||||||
pledge("dns flock inet rpath stdio tty", "")
|
|
||||||
.or_else(pledge::Error::ignore_platform)
|
|
||||||
.expect("Could not pledge permissions");
|
|
||||||
|
|
||||||
invite_users(&config, &mut client, config.get_ldap_sync_loop())
|
invite_users(&config, &mut client, config.get_ldap_sync_loop())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,7 +68,7 @@ fn ldap_client(
|
|||||||
let settings = LdapConnSettings::new()
|
let settings = LdapConnSettings::new()
|
||||||
.set_starttls(starttls)
|
.set_starttls(starttls)
|
||||||
.set_no_tls_verify(no_tls_verify);
|
.set_no_tls_verify(no_tls_verify);
|
||||||
let mut ldap = LdapConn::with_settings(settings, ldap_url.as_str())
|
let ldap = LdapConn::with_settings(settings, ldap_url.as_str())
|
||||||
.context("Failed to connect to LDAP server")?;
|
.context("Failed to connect to LDAP server")?;
|
||||||
ldap.simple_bind(bind_dn.as_str(), bind_pw.as_str())
|
ldap.simple_bind(bind_dn.as_str(), bind_pw.as_str())
|
||||||
.context("Could not bind to LDAP server")?;
|
.context("Could not bind to LDAP server")?;
|
||||||
@ -92,7 +78,7 @@ fn ldap_client(
|
|||||||
|
|
||||||
/// Retrieves search results from ldap
|
/// Retrieves search results from ldap
|
||||||
fn search_entries(config: &config::Config) -> Result<Vec<SearchEntry>, AnyError> {
|
fn search_entries(config: &config::Config) -> Result<Vec<SearchEntry>, AnyError> {
|
||||||
let mut ldap = ldap_client(
|
let ldap = ldap_client(
|
||||||
config.get_ldap_url(),
|
config.get_ldap_url(),
|
||||||
config.get_ldap_bind_dn(),
|
config.get_ldap_bind_dn(),
|
||||||
config.get_ldap_bind_password(),
|
config.get_ldap_bind_password(),
|
||||||
@ -104,13 +90,13 @@ fn search_entries(config: &config::Config) -> Result<Vec<SearchEntry>, AnyError>
|
|||||||
let mail_field = config.get_ldap_mail_field();
|
let mail_field = config.get_ldap_mail_field();
|
||||||
let fields = vec!["uid", "givenname", "sn", "cn", mail_field.as_str()];
|
let fields = vec!["uid", "givenname", "sn", "cn", mail_field.as_str()];
|
||||||
|
|
||||||
// Something something error handling
|
// TODO: Something something error handling
|
||||||
let (results, _res) = ldap
|
let (results, _res) = ldap
|
||||||
.with_search_options(SearchOptions::new().deref(DerefAliases::Always))
|
.with_search_options(SearchOptions::new().deref(DerefAliases::Always))
|
||||||
.search(
|
.search(
|
||||||
config.get_ldap_search_base_dn().as_str(),
|
&config.get_ldap_search_base_dn().as_str(),
|
||||||
Scope::Subtree,
|
Scope::Subtree,
|
||||||
config.get_ldap_search_filter().as_str(),
|
&config.get_ldap_search_filter().as_str(),
|
||||||
fields,
|
fields,
|
||||||
)
|
)
|
||||||
.context("LDAP search failure")?
|
.context("LDAP search failure")?
|
||||||
|
@ -2,7 +2,7 @@ extern crate reqwest;
|
|||||||
extern crate serde;
|
extern crate serde;
|
||||||
extern crate thiserror;
|
extern crate thiserror;
|
||||||
|
|
||||||
use reqwest::blocking::Response;
|
use reqwest::Response;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
@ -23,9 +23,9 @@ pub enum ResponseError {
|
|||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
pub struct User {
|
pub struct User {
|
||||||
#[serde(alias = "Email")]
|
#[serde(rename = "Email")]
|
||||||
email: String,
|
email: String,
|
||||||
#[serde(rename = "_status", alias = "_Status")]
|
#[serde(rename = "_Status")]
|
||||||
status: i32,
|
status: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -72,9 +72,8 @@ impl Client {
|
|||||||
reqwest::Certificate::from_der(&buf).expect("Could not load DER root cert file")
|
reqwest::Certificate::from_der(&buf).expect("Could not load DER root cert file")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_http_client(&self) -> reqwest::blocking::Client {
|
fn get_http_client(&self) -> reqwest::Client {
|
||||||
let mut client =
|
let mut client = reqwest::Client::builder().redirect(reqwest::RedirectPolicy::none());
|
||||||
reqwest::blocking::Client::builder().redirect(reqwest::redirect::Policy::none());
|
|
||||||
|
|
||||||
if !&self.root_cert_file.is_empty() {
|
if !&self.root_cert_file.is_empty() {
|
||||||
let cert = self.get_root_cert();
|
let cert = self.get_root_cert();
|
||||||
|
Loading…
Reference in New Issue
Block a user