Compare commits
28 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1b2dfbe52e | ||
|
|
e1aa2bfb18 | ||
|
|
1377d5aed9 | ||
|
|
fa0185af5e | ||
|
|
d720a7812a | ||
|
|
d2dec56cca | ||
|
|
ab2da7b975 | ||
|
|
8f69e4badd | ||
|
|
5bd00f24a2 | ||
|
|
ab9ee8d962 | ||
|
|
852e1586e7 | ||
|
|
23b388f3b8 | ||
|
|
22ae2c7124 | ||
|
|
5ad63d31d3 | ||
|
|
d55d4487ed | ||
|
|
4283d27da6 | ||
|
|
4576cf9f2c | ||
|
|
d1d5d38b32 | ||
|
|
e5ce98c874 | ||
|
|
96b7dbb1c5 | ||
|
|
9408b12bc7 | ||
|
|
4e85a4718f | ||
|
|
d1f1eb8e80 | ||
|
|
da364746c4 | ||
|
|
d672f68049 | ||
|
|
dcca768b6c | ||
|
|
ea69b4bead | ||
|
|
7b4188a376 |
@@ -34,12 +34,20 @@ package.json
|
||||
.vscode
|
||||
.devcontainer
|
||||
|
||||
# Created databases
|
||||
*.db
|
||||
*.db-shm
|
||||
*.db-wal
|
||||
|
||||
# These are backup files generated by rustfmt
|
||||
**/*.rs.bk
|
||||
|
||||
# Various config files that shouldn't be tracked
|
||||
.env
|
||||
lldap_config.toml
|
||||
server_key
|
||||
users.db*
|
||||
screenshot.png
|
||||
recipe.json
|
||||
lldap_config.toml
|
||||
cert.pem
|
||||
key.pem
|
||||
|
||||
2
.github/codecov.yml
vendored
2
.github/codecov.yml
vendored
@@ -10,3 +10,5 @@ ignore:
|
||||
- "docs"
|
||||
- "example_configs"
|
||||
- "migration-tool"
|
||||
- "scripts"
|
||||
- "set-password"
|
||||
|
||||
14
.github/workflows/Dockerfile.ci.alpine
vendored
14
.github/workflows/Dockerfile.ci.alpine
vendored
@@ -11,10 +11,10 @@ RUN mkdir -p /lldap/app
|
||||
|
||||
RUN if [ "${TARGETPLATFORM}" = "linux/amd64" ]; then \
|
||||
mv bin/x86_64-unknown-linux-musl-lldap-bin/lldap target/lldap && \
|
||||
mv bin/x86_64-unknown-linux-musl-migration-tool-bin/migration-tool target/migration-tool && \
|
||||
mv bin/x86_64-unknown-linux-musl-lldap_migration_tool-bin/lldap_migration_tool target/lldap_migration_tool && \
|
||||
mv bin/x86_64-unknown-linux-musl-lldap_set_password-bin/lldap_set_password target/lldap_set_password && \
|
||||
chmod +x target/lldap && \
|
||||
chmod +x target/migration-tool && \
|
||||
chmod +x target/lldap_migration_tool && \
|
||||
chmod +x target/lldap_set_password && \
|
||||
ls -la target/ . && \
|
||||
pwd \
|
||||
@@ -22,10 +22,10 @@ RUN if [ "${TARGETPLATFORM}" = "linux/amd64" ]; then \
|
||||
|
||||
RUN if [ "${TARGETPLATFORM}" = "linux/arm64" ]; then \
|
||||
mv bin/aarch64-unknown-linux-musl-lldap-bin/lldap target/lldap && \
|
||||
mv bin/aarch64-unknown-linux-musl-migration-tool-bin/migration-tool target/migration-tool && \
|
||||
mv bin/aarch64-unknown-linux-musl-lldap_migration_tool-bin/lldap_migration_tool target/lldap_migration_tool && \
|
||||
mv bin/aarch64-unknown-linux-musl-lldap_set_password-bin/lldap_set_password target/lldap_set_password && \
|
||||
chmod +x target/lldap && \
|
||||
chmod +x target/migration-tool && \
|
||||
chmod +x target/lldap_migration_tool && \
|
||||
chmod +x target/lldap_set_password && \
|
||||
ls -la target/ . && \
|
||||
pwd \
|
||||
@@ -33,10 +33,10 @@ RUN if [ "${TARGETPLATFORM}" = "linux/arm64" ]; then \
|
||||
|
||||
RUN if [ "${TARGETPLATFORM}" = "linux/arm/v7" ]; then \
|
||||
mv bin/armv7-unknown-linux-gnueabihf-lldap-bin/lldap target/lldap && \
|
||||
mv bin/armv7-unknown-linux-gnueabihf-migration-tool-bin/migration-tool target/migration-tool && \
|
||||
mv bin/armv7-unknown-linux-gnueabihf-lldap_migration_tool-bin/lldap_migration_tool target/lldap_migration_tool && \
|
||||
mv bin/armv7-unknown-linux-gnueabihf-lldap_set_password-bin/lldap_set_password target/lldap_set_password && \
|
||||
chmod +x target/lldap && \
|
||||
chmod +x target/migration-tool && \
|
||||
chmod +x target/lldap_migration_tool && \
|
||||
chmod +x target/lldap_set_password && \
|
||||
ls -la target/ . && \
|
||||
pwd \
|
||||
@@ -47,7 +47,7 @@ COPY docker-entrypoint.sh /docker-entrypoint.sh
|
||||
COPY lldap_config.docker_template.toml /lldap/
|
||||
COPY web/index_local.html web/index.html
|
||||
RUN cp target/lldap /lldap/ && \
|
||||
cp target/migration-tool /lldap/ && \
|
||||
cp target/lldap_migration_tool /lldap/ && \
|
||||
cp target/lldap_set_password /lldap/ && \
|
||||
cp -R web/index.html \
|
||||
web/pkg \
|
||||
|
||||
14
.github/workflows/Dockerfile.ci.debian
vendored
14
.github/workflows/Dockerfile.ci.debian
vendored
@@ -11,10 +11,10 @@ RUN mkdir -p /lldap/app
|
||||
|
||||
RUN if [ "${TARGETPLATFORM}" = "linux/amd64" ]; then \
|
||||
mv bin/x86_64-unknown-linux-musl-lldap-bin/lldap target/lldap && \
|
||||
mv bin/x86_64-unknown-linux-musl-migration-tool-bin/migration-tool target/migration-tool && \
|
||||
mv bin/x86_64-unknown-linux-musl-lldap_migration_tool-bin/lldap_migration_tool target/lldap_migration_tool && \
|
||||
mv bin/x86_64-unknown-linux-musl-lldap_set_password-bin/lldap_set_password target/lldap_set_password && \
|
||||
chmod +x target/lldap && \
|
||||
chmod +x target/migration-tool && \
|
||||
chmod +x target/lldap_migration_tool && \
|
||||
chmod +x target/lldap_set_password && \
|
||||
ls -la target/ . && \
|
||||
pwd \
|
||||
@@ -22,10 +22,10 @@ RUN if [ "${TARGETPLATFORM}" = "linux/amd64" ]; then \
|
||||
|
||||
RUN if [ "${TARGETPLATFORM}" = "linux/arm64" ]; then \
|
||||
mv bin/aarch64-unknown-linux-musl-lldap-bin/lldap target/lldap && \
|
||||
mv bin/aarch64-unknown-linux-musl-migration-tool-bin/migration-tool target/migration-tool && \
|
||||
mv bin/aarch64-unknown-linux-musl-lldap_migration_tool-bin/lldap_migration_tool target/lldap_migration_tool && \
|
||||
mv bin/aarch64-unknown-linux-musl-lldap_set_password-bin/lldap_set_password target/lldap_set_password && \
|
||||
chmod +x target/lldap && \
|
||||
chmod +x target/migration-tool && \
|
||||
chmod +x target/lldap_migration_tool && \
|
||||
chmod +x target/lldap_set_password && \
|
||||
ls -la target/ . && \
|
||||
pwd \
|
||||
@@ -33,10 +33,10 @@ RUN if [ "${TARGETPLATFORM}" = "linux/arm64" ]; then \
|
||||
|
||||
RUN if [ "${TARGETPLATFORM}" = "linux/arm/v7" ]; then \
|
||||
mv bin/armv7-unknown-linux-gnueabihf-lldap-bin/lldap target/lldap && \
|
||||
mv bin/armv7-unknown-linux-gnueabihf-migration-tool-bin/migration-tool target/migration-tool && \
|
||||
mv bin/armv7-unknown-linux-gnueabihf-lldap_migration_tool-bin/lldap_migration_tool target/lldap_migration_tool && \
|
||||
mv bin/armv7-unknown-linux-gnueabihf-lldap_set_password-bin/lldap_set_password target/lldap_set_password && \
|
||||
chmod +x target/lldap && \
|
||||
chmod +x target/migration-tool && \
|
||||
chmod +x target/lldap_migration_tool && \
|
||||
chmod +x target/lldap_set_password && \
|
||||
ls -la target/ . && \
|
||||
pwd \
|
||||
@@ -47,7 +47,7 @@ COPY docker-entrypoint.sh /docker-entrypoint.sh
|
||||
COPY lldap_config.docker_template.toml /lldap/
|
||||
COPY web/index_local.html web/index.html
|
||||
RUN cp target/lldap /lldap/ && \
|
||||
cp target/migration-tool /lldap/ && \
|
||||
cp target/lldap_migration_tool /lldap/ && \
|
||||
cp target/lldap_set_password /lldap/ && \
|
||||
cp -R web/index.html \
|
||||
web/pkg \
|
||||
|
||||
26
.github/workflows/docker-build-static.yml
vendored
26
.github/workflows/docker-build-static.yml
vendored
@@ -89,7 +89,7 @@ jobs:
|
||||
image: nitnelave/rust-dev:latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3.5.0
|
||||
uses: actions/checkout@v3.5.2
|
||||
- uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
@@ -138,7 +138,7 @@ jobs:
|
||||
CARGO_HOME: ${GITHUB_WORKSPACE}/.cargo
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3.5.0
|
||||
uses: actions/checkout@v3.5.2
|
||||
- uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
@@ -151,7 +151,7 @@ jobs:
|
||||
restore-keys: |
|
||||
lldap-bin-${{ matrix.target }}-
|
||||
- name: Compile ${{ matrix.target }} lldap and tools
|
||||
run: cargo build --target=${{ matrix.target }} --release -p lldap -p migration-tool -p lldap_set_password
|
||||
run: cargo build --target=${{ matrix.target }} --release -p lldap -p lldap_migration_tool -p lldap_set_password
|
||||
- name: Check path
|
||||
run: ls -al target/release
|
||||
- name: Upload ${{ matrix.target}} lldap artifacts
|
||||
@@ -162,8 +162,8 @@ jobs:
|
||||
- name: Upload ${{ matrix.target }} migration tool artifacts
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: ${{ matrix.target }}-migration-tool-bin
|
||||
path: target/${{ matrix.target }}/release/migration-tool
|
||||
name: ${{ matrix.target }}-lldap_migration_tool-bin
|
||||
path: target/${{ matrix.target }}/release/lldap_migration_tool
|
||||
- name: Upload ${{ matrix.target }} password tool artifacts
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
@@ -477,7 +477,7 @@ jobs:
|
||||
packages: write
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3.5.0
|
||||
uses: actions/checkout@v3.5.2
|
||||
- name: Download all artifacts
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
@@ -594,14 +594,14 @@ jobs:
|
||||
mv bin/aarch64-unknown-linux-musl-lldap-bin/lldap bin/aarch64-lldap
|
||||
mv bin/x86_64-unknown-linux-musl-lldap-bin/lldap bin/amd64-lldap
|
||||
mv bin/armv7-unknown-linux-gnueabihf-lldap-bin/lldap bin/armhf-lldap
|
||||
mv bin/aarch64-unknown-linux-musl-migration-tool-bin/migration-tool bin/aarch64-migration-tool
|
||||
mv bin/x86_64-unknown-linux-musl-migration-tool-bin/migration-tool bin/amd64-migration-tool
|
||||
mv bin/armv7-unknown-linux-gnueabihf-migration-tool-bin/migration-tool bin/armhf-migration-tool
|
||||
mv bin/aarch64-unknown-linux-musl-lldap_migration_tool-bin/lldap_migration_tool bin/aarch64-lldap_migration_tool
|
||||
mv bin/x86_64-unknown-linux-musl-lldap_migration_tool-bin/lldap_migration_tool bin/amd64-lldap_migration_tool
|
||||
mv bin/armv7-unknown-linux-gnueabihf-lldap_migration_tool-bin/lldap_migration_tool bin/armhf-lldap_migration_tool
|
||||
mv bin/aarch64-unknown-linux-musl-lldap_set_password-bin/lldap_set_password bin/aarch64-lldap_set_password
|
||||
mv bin/x86_64-unknown-linux-musl-lldap_set_password-bin/lldap_set_password bin/amd64-lldap_set_password
|
||||
mv bin/armv7-unknown-linux-gnueabihf-lldap_set_password-bin/lldap_set_password bin/armhf-lldap_set_password
|
||||
chmod +x bin/*-lldap
|
||||
chmod +x bin/*-migration-tool
|
||||
chmod +x bin/*-lldap_migration_tool
|
||||
chmod +x bin/*-lldap_set_password
|
||||
|
||||
- name: Download llap ui artifacts
|
||||
@@ -627,9 +627,9 @@ jobs:
|
||||
mv bin/aarch64-lldap aarch64-lldap/lldap
|
||||
mv bin/amd64-lldap amd64-lldap/lldap
|
||||
mv bin/armhf-lldap armhf-lldap/lldap
|
||||
mv bin/aarch64-migration-tool aarch64-lldap/migration-tool
|
||||
mv bin/amd64-migration-tool amd64-lldap/migration-tool
|
||||
mv bin/armhf-migration-tool armhf-lldap/migration-tool
|
||||
mv bin/aarch64-lldap_migration_tool aarch64-lldap/lldap_migration_tool
|
||||
mv bin/amd64-lldap_migration_tool amd64-lldap/lldap_migration_tool
|
||||
mv bin/armhf-lldap_migration_tool armhf-lldap/lldap_migration_tool
|
||||
mv bin/aarch64-lldap_set_password aarch64-lldap/lldap_set_password
|
||||
mv bin/amd64-lldap_set_password amd64-lldap/lldap_set_password
|
||||
mv bin/armhf-lldap_set_password armhf-lldap/lldap_set_password
|
||||
|
||||
33
.github/workflows/rust.yml
vendored
33
.github/workflows/rust.yml
vendored
@@ -33,7 +33,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout sources
|
||||
uses: actions/checkout@v3.5.0
|
||||
uses: actions/checkout@v3.5.2
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
- name: Build
|
||||
run: cargo build --verbose --workspace
|
||||
@@ -52,7 +52,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout sources
|
||||
uses: actions/checkout@v3.5.0
|
||||
uses: actions/checkout@v3.5.2
|
||||
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
|
||||
@@ -69,7 +69,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout sources
|
||||
uses: actions/checkout@v3.5.0
|
||||
uses: actions/checkout@v3.5.2
|
||||
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
|
||||
@@ -86,7 +86,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout sources
|
||||
uses: actions/checkout@v3.5.0
|
||||
uses: actions/checkout@v3.5.2
|
||||
|
||||
- name: Install Rust
|
||||
run: rustup toolchain install nightly --component llvm-tools-preview && rustup component add llvm-tools-preview --toolchain stable-x86_64-unknown-linux-gnu
|
||||
@@ -112,3 +112,28 @@ jobs:
|
||||
files: lcov.info
|
||||
fail_ci_if_error: true
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
|
||||
publish-crates:
|
||||
name: Publish on crates.io
|
||||
if: ${{ needs.pre_job.outputs.should_skip != 'true' || (github.event_name == 'push' && github.ref == 'refs/heads/main') || github.event_name == 'release' }}
|
||||
needs: pre_job
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
target: [lldap_auth, lldap, lldap_app, lldap_set_password, lldap_migration_tool]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3.5.2
|
||||
- uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
override: true
|
||||
- name: Publish ${{ matrix.target }} crate
|
||||
uses: katyo/publish-crates@v2
|
||||
with:
|
||||
args: -p ${{ matrix.target }}
|
||||
dry-run: ${{ github.event_name != 'release' }}
|
||||
check-repo: ${{ github.event_name != 'pull_request' }}
|
||||
registry-token: ${{ secrets.CARGO_REGISTRY_TOKEN }}
|
||||
ignore-unpublished-changes: ${{ github.event_name != 'release' }}
|
||||
|
||||
|
||||
372
Cargo.lock
generated
372
Cargo.lock
generated
@@ -118,7 +118,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "465a6172cf69b960917811022d8f29bc0b7fa1398bc4f78b3c466673db1213b6"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -189,7 +189,7 @@ dependencies = [
|
||||
"pin-project-lite",
|
||||
"tokio-rustls",
|
||||
"tokio-util",
|
||||
"webpki-roots",
|
||||
"webpki-roots 0.22.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -252,7 +252,7 @@ dependencies = [
|
||||
"actix-router",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -278,7 +278,7 @@ checksum = "6d44b8fee1ced9671ba043476deddef739dd0959bf77030b26b738cc591737a7"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -400,7 +400,7 @@ checksum = "726535892e8eae7e70657b4c8ea93d26b8553afb1ce617caee529ef96d7dee6c"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 1.0.109",
|
||||
"synstructure",
|
||||
]
|
||||
|
||||
@@ -412,7 +412,21 @@ checksum = "2777730b2039ac0f95f093556e61b6d26cebed5393ca6f152717777cec3a42ed"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "assert_cmd"
|
||||
version = "2.0.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9834fcc22e0874394a010230586367d4a3e9f11b560f469262678547e1d2575e"
|
||||
dependencies = [
|
||||
"bstr",
|
||||
"doc-comment",
|
||||
"predicates",
|
||||
"predicates-core",
|
||||
"predicates-tree",
|
||||
"wait-timeout",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -434,7 +448,7 @@ checksum = "e4655ae1a7b0cdf149156f780c5bf3f1352bc53cbd9e0a361a7ef7b22947e965"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -445,7 +459,7 @@ checksum = "1cd7fce9ba8c3c042128ce72d8b2ddbf3a05747efb67ea0313c635e10bda47a2"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -497,7 +511,7 @@ dependencies = [
|
||||
"proc-macro-error",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -606,6 +620,18 @@ dependencies = [
|
||||
"uuid 0.8.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bstr"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3d4260bcc2e8fc9df1eac4919a720effeb63a3f0952f5bf4944adfa18897f09"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"once_cell",
|
||||
"regex-automata",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.12.0"
|
||||
@@ -695,7 +721,7 @@ dependencies = [
|
||||
"proc-macro-error",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -958,7 +984,7 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"scratch",
|
||||
"syn",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -975,7 +1001,7 @@ checksum = "086c685979a698443656e5cf7856c95c642295a38599f12fb1ff76fb28d19892"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -999,7 +1025,7 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"strsim",
|
||||
"syn",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1010,7 +1036,20 @@ checksum = "b36230598a2d5de7ec1c6f51f72d8a99a9208daff41de2084d06e3fd3ea56685"
|
||||
dependencies = [
|
||||
"darling_core",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dashmap"
|
||||
version = "5.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "907076dfda823b0b36d2a1bb5f90c96660a5bbcd7729e10727f07858f22c4edc"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"hashbrown 0.12.3",
|
||||
"lock_api",
|
||||
"once_cell",
|
||||
"parking_lot_core 0.9.7",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1062,7 +1101,7 @@ dependencies = [
|
||||
"darling",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1072,7 +1111,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ebcda35c7a396850a55ffeac740804b40ffec779b98fffbb1738f4033f0ee79e"
|
||||
dependencies = [
|
||||
"derive_builder_core",
|
||||
"syn",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1085,7 +1124,7 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"rustc_version",
|
||||
"syn",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1096,7 +1135,7 @@ checksum = "532b4c15dccee12c7044f1fcad956e98410860b22231e44a3b827464797ca7bf"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1153,7 +1192,7 @@ checksum = "adc2ab4d5a16117f9029e9a6b5e4e79f4c67f6519bc134210d4d4a04ba31f41b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1164,9 +1203,15 @@ checksum = "3bf95dc3f046b9da4f2d51833c0d3547d8564ef6910f5c1ed130306a75b92886"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "doc-comment"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10"
|
||||
|
||||
[[package]]
|
||||
name = "dotenvy"
|
||||
version = "0.15.6"
|
||||
@@ -1255,7 +1300,7 @@ checksum = "aa4da3c766cd7a0db8242e326e9e4e081edd567072893ed320008189715366a4"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 1.0.109",
|
||||
"synstructure",
|
||||
]
|
||||
|
||||
@@ -1349,6 +1394,16 @@ version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6c2141d6d6c8512188a7891b4b01590a45f6dac67afb4f255c4124dbb86d4eaa"
|
||||
|
||||
[[package]]
|
||||
name = "fslock"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "04412b8935272e3a9bae6f48c7bfff74c2911f60525404edfdd28e49884c3bfb"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures"
|
||||
version = "0.3.26"
|
||||
@@ -1388,7 +1443,7 @@ checksum = "3422d14de7903a52e9dbc10ae05a7e14445ec61890100e098754e120b2bd7b1e"
|
||||
dependencies = [
|
||||
"derive_utils",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1427,7 +1482,7 @@ checksum = "95a73af87da33b5acf53acfebdc339fe592ecf5357ac7c0a7734ab9d8c876a70"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1718,7 +1773,7 @@ dependencies = [
|
||||
"quote",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"syn",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1735,7 +1790,7 @@ dependencies = [
|
||||
"quote",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"syn",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1746,7 +1801,7 @@ checksum = "e56b093bfda71de1da99758b036f4cc811fd2511c8a76f75680e9ffbd2bb4251"
|
||||
dependencies = [
|
||||
"graphql_client_codegen 0.10.0",
|
||||
"proc-macro2",
|
||||
"syn",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1757,7 +1812,7 @@ checksum = "a755cc59cda2641ea3037b4f9f7ef40471c329f55c1fa2db6fa0bb7ae6c1f7ce"
|
||||
dependencies = [
|
||||
"graphql_client_codegen 0.11.0",
|
||||
"proc-macro2",
|
||||
"syn",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2162,7 +2217,7 @@ dependencies = [
|
||||
"proc-macro-error",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2268,7 +2323,7 @@ dependencies = [
|
||||
"peg",
|
||||
"tokio-util",
|
||||
"tracing",
|
||||
"uuid 1.3.0",
|
||||
"uuid 1.3.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2296,7 +2351,7 @@ dependencies = [
|
||||
"socket2",
|
||||
"tokio",
|
||||
"tokio-rustls",
|
||||
"webpki-roots",
|
||||
"webpki-roots 0.22.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2345,7 +2400,7 @@ checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4"
|
||||
|
||||
[[package]]
|
||||
name = "lldap"
|
||||
version = "0.4.3-alpha"
|
||||
version = "0.5.0-alpha"
|
||||
dependencies = [
|
||||
"actix",
|
||||
"actix-files",
|
||||
@@ -2357,6 +2412,7 @@ dependencies = [
|
||||
"actix-web",
|
||||
"actix-web-httpauth",
|
||||
"anyhow",
|
||||
"assert_cmd",
|
||||
"async-trait",
|
||||
"base64 0.21.0",
|
||||
"bincode",
|
||||
@@ -2368,6 +2424,7 @@ dependencies = [
|
||||
"figment_file_provider_adapter",
|
||||
"futures",
|
||||
"futures-util",
|
||||
"graphql_client 0.11.0",
|
||||
"hmac 0.12.1",
|
||||
"http",
|
||||
"image",
|
||||
@@ -2375,14 +2432,17 @@ dependencies = [
|
||||
"juniper",
|
||||
"jwt 0.16.0",
|
||||
"lber 0.4.1",
|
||||
"ldap3",
|
||||
"ldap3_proto",
|
||||
"lettre",
|
||||
"lldap_auth",
|
||||
"lldap_auth 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log",
|
||||
"mockall",
|
||||
"nix",
|
||||
"opaque-ke",
|
||||
"orion",
|
||||
"rand 0.8.5",
|
||||
"rand_chacha 0.3.1",
|
||||
"reqwest",
|
||||
"rustls",
|
||||
"rustls-pemfile",
|
||||
@@ -2391,6 +2451,7 @@ dependencies = [
|
||||
"serde",
|
||||
"serde_bytes",
|
||||
"serde_json",
|
||||
"serial_test",
|
||||
"sha2 0.10.6",
|
||||
"thiserror",
|
||||
"time 0.3.19",
|
||||
@@ -2405,13 +2466,13 @@ dependencies = [
|
||||
"tracing-log",
|
||||
"tracing-subscriber",
|
||||
"urlencoding",
|
||||
"uuid 1.3.0",
|
||||
"webpki-roots",
|
||||
"uuid 1.3.1",
|
||||
"webpki-roots 0.23.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lldap_app"
|
||||
version = "0.4.3-alpha"
|
||||
version = "0.5.0-alpha"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"base64 0.13.1",
|
||||
@@ -2424,13 +2485,13 @@ dependencies = [
|
||||
"image",
|
||||
"indexmap",
|
||||
"jwt 0.13.0",
|
||||
"lldap_auth",
|
||||
"lldap_auth 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.8.5",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"url-escape",
|
||||
"validator",
|
||||
"validator_derive",
|
||||
"validator_derive 0.16.0",
|
||||
"wasm-bindgen",
|
||||
"wasm-bindgen-futures",
|
||||
"web-sys",
|
||||
@@ -2457,13 +2518,49 @@ dependencies = [
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lldap_auth"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c17867a28e09989643401bb7849a494b328416634a335ddf7d3dabc9806ba563"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"curve25519-dalek",
|
||||
"digest 0.9.0",
|
||||
"generic-array",
|
||||
"getrandom 0.2.8",
|
||||
"opaque-ke",
|
||||
"rand 0.8.5",
|
||||
"rust-argon2",
|
||||
"serde",
|
||||
"sha2 0.9.9",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lldap_migration_tool"
|
||||
version = "0.4.2"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"base64 0.13.1",
|
||||
"graphql_client 0.11.0",
|
||||
"ldap3",
|
||||
"lldap_auth 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.8.5",
|
||||
"requestty",
|
||||
"reqwest",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"smallvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lldap_set_password"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap",
|
||||
"lldap_auth",
|
||||
"lldap_auth 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.8.5",
|
||||
"reqwest",
|
||||
"serde",
|
||||
@@ -2538,20 +2635,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
|
||||
|
||||
[[package]]
|
||||
name = "migration-tool"
|
||||
version = "0.4.2"
|
||||
name = "memoffset"
|
||||
version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"base64 0.13.1",
|
||||
"graphql_client 0.11.0",
|
||||
"ldap3",
|
||||
"lldap_auth",
|
||||
"rand 0.8.5",
|
||||
"requestty",
|
||||
"reqwest",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"smallvec",
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2621,7 +2710,21 @@ dependencies = [
|
||||
"cfg-if",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nix"
|
||||
version = "0.26.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bfdda3d196821d6af13126e40375cdf7da646a96114af134d5f417a9a1dc8e1a"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"memoffset",
|
||||
"pin-utils",
|
||||
"static_assertions",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2831,7 +2934,7 @@ dependencies = [
|
||||
"proc-macro-error",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2914,7 +3017,7 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
"proc-macro2-diagnostics",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2976,7 +3079,7 @@ checksum = "069bdb1e05adc7a8990dce9cc75370895fbe4e3d58b9b73bf1aee56359344a55"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3064,7 +3167,7 @@ dependencies = [
|
||||
"proc-macro-error-attr",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 1.0.109",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
@@ -3081,9 +3184,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.51"
|
||||
version = "1.0.54"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5d727cae5b39d21da60fa540906919ad737832fe0b1c165da3a34d6548c849d6"
|
||||
checksum = "e472a104799c74b514a57226160104aa483546de37e839ec50e3c2e41dd87534"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
@@ -3096,16 +3199,16 @@ checksum = "4bf29726d67464d49fa6224a1d07936a8c08bb3fba727c7493f6cf1616fdaada"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 1.0.109",
|
||||
"version_check",
|
||||
"yansi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.23"
|
||||
version = "1.0.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b"
|
||||
checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
@@ -3301,7 +3404,7 @@ dependencies = [
|
||||
"wasm-bindgen",
|
||||
"wasm-bindgen-futures",
|
||||
"web-sys",
|
||||
"webpki-roots",
|
||||
"webpki-roots 0.22.6",
|
||||
"winreg",
|
||||
]
|
||||
|
||||
@@ -3429,6 +3532,16 @@ dependencies = [
|
||||
"base64 0.21.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls-webpki"
|
||||
version = "0.100.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d6207cd5ed3d8dca7816f8f3725513a34609c0c765bf652b8c3cb4cfd87db46b"
|
||||
dependencies = [
|
||||
"ring",
|
||||
"untrusted",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustversion"
|
||||
version = "1.0.11"
|
||||
@@ -3499,7 +3612,7 @@ dependencies = [
|
||||
"thiserror",
|
||||
"tracing",
|
||||
"url",
|
||||
"uuid 1.3.0",
|
||||
"uuid 1.3.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3512,7 +3625,7 @@ dependencies = [
|
||||
"heck 0.3.3",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3523,7 +3636,7 @@ checksum = "d2fbe015dbdaa7d8829d71c1e14fb6289e928ac256b93dfda543c85cd89d6f03"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"sea-query-derive",
|
||||
"uuid 1.3.0",
|
||||
"uuid 1.3.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3535,7 +3648,7 @@ dependencies = [
|
||||
"chrono",
|
||||
"sea-query",
|
||||
"sqlx",
|
||||
"uuid 1.3.0",
|
||||
"uuid 1.3.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3547,7 +3660,7 @@ dependencies = [
|
||||
"heck 0.4.1",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 1.0.109",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
@@ -3570,7 +3683,7 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"rustversion",
|
||||
"syn",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3650,7 +3763,7 @@ checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3677,6 +3790,30 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serial_test"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0e56dd856803e253c8f298af3f4d7eb0ae5e23a737252cd90bb4f3b435033b2d"
|
||||
dependencies = [
|
||||
"dashmap",
|
||||
"fslock",
|
||||
"lazy_static",
|
||||
"parking_lot 0.12.1",
|
||||
"serial_test_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serial_test_derive"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "91d129178576168c589c9ec973feedf7d3126c01ac2bf08795109aa35b69fb8f"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.12",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha1"
|
||||
version = "0.10.5"
|
||||
@@ -3895,8 +4032,8 @@ dependencies = [
|
||||
"thiserror",
|
||||
"tokio-stream",
|
||||
"url",
|
||||
"uuid 1.3.0",
|
||||
"webpki-roots",
|
||||
"uuid 1.3.1",
|
||||
"webpki-roots 0.22.6",
|
||||
"whoami",
|
||||
]
|
||||
|
||||
@@ -3914,7 +4051,7 @@ dependencies = [
|
||||
"quote",
|
||||
"sqlx-core",
|
||||
"sqlx-rt",
|
||||
"syn",
|
||||
"syn 1.0.109",
|
||||
"url",
|
||||
]
|
||||
|
||||
@@ -3968,6 +4105,17 @@ dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "79d9531f94112cfc3e4c8f5f02cb2b58f72c97b7efd85f70203cc6d8efda5927"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "synstructure"
|
||||
version = "0.12.6"
|
||||
@@ -3976,7 +4124,7 @@ checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 1.0.109",
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
@@ -4037,7 +4185,7 @@ checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -4131,7 +4279,7 @@ checksum = "d266c00fde287f55d3f1c3e96c500c362a2b8c695076ec180f27918820bc6df8"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -4207,7 +4355,7 @@ dependencies = [
|
||||
"actix-web",
|
||||
"pin-project",
|
||||
"tracing",
|
||||
"uuid 1.3.0",
|
||||
"uuid 1.3.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -4218,7 +4366,7 @@ checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -4408,9 +4556,9 @@ checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7"
|
||||
|
||||
[[package]]
|
||||
name = "uuid"
|
||||
version = "1.3.0"
|
||||
version = "1.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1674845326ee10d37ca60470760d4288a6f80f304007d92e5c53bab78c9cfd79"
|
||||
checksum = "5b55a3fef2a1e3b3a00ce878640918820d3c51081576ac657d23af9fc7928fdb"
|
||||
dependencies = [
|
||||
"getrandom 0.2.8",
|
||||
"md-5",
|
||||
@@ -4429,7 +4577,7 @@ dependencies = [
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
"url",
|
||||
"validator_types",
|
||||
"validator_types 0.14.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -4444,8 +4592,24 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"regex",
|
||||
"syn",
|
||||
"validator_types",
|
||||
"syn 1.0.109",
|
||||
"validator_types 0.14.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "validator_derive"
|
||||
version = "0.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bc44ca3088bb3ba384d9aecf40c6a23a676ce23e09bdaca2073d99c207f864af"
|
||||
dependencies = [
|
||||
"if_chain",
|
||||
"lazy_static",
|
||||
"proc-macro-error",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"regex",
|
||||
"syn 1.0.109",
|
||||
"validator_types 0.16.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -4455,7 +4619,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ded9d97e1d42327632f5f3bae6403c04886e2de3036261ef42deebd931a6a291"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"syn",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "validator_types"
|
||||
version = "0.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "111abfe30072511849c5910134e8baf8dc05de4c0e5903d681cbd5c9c4d611e3"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -4482,6 +4656,15 @@ version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
|
||||
|
||||
[[package]]
|
||||
name = "wait-timeout"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "want"
|
||||
version = "0.3.0"
|
||||
@@ -4531,7 +4714,7 @@ dependencies = [
|
||||
"once_cell",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 1.0.109",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
@@ -4565,7 +4748,7 @@ checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 1.0.109",
|
||||
"wasm-bindgen-backend",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
@@ -4605,6 +4788,15 @@ dependencies = [
|
||||
"webpki",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "webpki-roots"
|
||||
version = "0.23.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "aa54963694b65584e170cf5dc46aeb4dcaa5584e652ff5f3952e56d66aff0125"
|
||||
dependencies = [
|
||||
"rustls-webpki",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "whoami"
|
||||
version = "1.3.0"
|
||||
@@ -4790,7 +4982,7 @@ dependencies = [
|
||||
"proc-macro-error",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -4821,7 +5013,7 @@ checksum = "39049d193b52eaad4ffc80916bf08806d142c90b5edcebd527644de438a7e19a"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -4831,7 +5023,7 @@ source = "git+https://github.com/jfbilodeau/yew_form?rev=4b9fabffb63393ec7626a44
|
||||
dependencies = [
|
||||
"gloo-console",
|
||||
"validator",
|
||||
"validator_derive",
|
||||
"validator_derive 0.14.0",
|
||||
"wasm-bindgen",
|
||||
"web-sys",
|
||||
"yew",
|
||||
@@ -4844,7 +5036,7 @@ source = "git+https://github.com/jfbilodeau/yew_form?rev=4b9fabffb63393ec7626a44
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 1.0.109",
|
||||
"yew_form",
|
||||
]
|
||||
|
||||
@@ -4865,7 +5057,7 @@ checksum = "44bf07cb3e50ea2003396695d58bf46bc9887a1f362260446fad6bc4e79bd36c"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 1.0.109",
|
||||
"synstructure",
|
||||
]
|
||||
|
||||
|
||||
@@ -31,12 +31,12 @@ FROM chef AS builder
|
||||
COPY --from=planner /tmp/recipe.json recipe.json
|
||||
RUN cargo chef cook --release -p lldap_app --target wasm32-unknown-unknown \
|
||||
&& cargo chef cook --release -p lldap \
|
||||
&& cargo chef cook --release -p migration-tool \
|
||||
&& cargo chef cook --release -p lldap_migration_tool \
|
||||
&& cargo chef cook --release -p lldap_set_password
|
||||
|
||||
# Copy the source and build the app and server.
|
||||
COPY --chown=app:app . .
|
||||
RUN cargo build --release -p lldap -p migration-tool -p lldap_set_password \
|
||||
RUN cargo build --release -p lldap -p lldap_migration_tool -p lldap_set_password \
|
||||
# Build the frontend.
|
||||
&& ./app/build.sh
|
||||
|
||||
@@ -78,7 +78,7 @@ WORKDIR /app
|
||||
COPY --from=builder /app/app/index_local.html app/index.html
|
||||
COPY --from=builder /app/app/static app/static
|
||||
COPY --from=builder /app/app/pkg app/pkg
|
||||
COPY --from=builder /app/target/release/lldap /app/target/release/migration-tool /app/target/release/lldap_set_password ./
|
||||
COPY --from=builder /app/target/release/lldap /app/target/release/lldap_migration_tool /app/target/release/lldap_set_password ./
|
||||
COPY docker-entrypoint.sh lldap_config.docker_template.toml ./
|
||||
|
||||
RUN set -x \
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
<a href="https://discord.gg/h5PEdRMNyP">
|
||||
<img alt="Discord" src="https://img.shields.io/discord/898492935446876200?label=discord&logo=discord" />
|
||||
</a>
|
||||
|
||||
<a href="https://twitter.com/nitnelave1?ref_src=twsrc%5Etfw">
|
||||
<img
|
||||
src="https://img.shields.io/twitter/follow/nitnelave1?style=social"
|
||||
@@ -26,6 +27,10 @@
|
||||
<a href="https://app.codecov.io/gh/lldap/lldap">
|
||||
<img alt="Codecov" src="https://img.shields.io/codecov/c/github/lldap/lldap" />
|
||||
</a>
|
||||
<br/>
|
||||
<a href="https://www.buymeacoffee.com/nitnelave" target="_blank">
|
||||
<img src="https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png" alt="Buy Me A Coffee" style="height: 41px !important;width: 174px !important;box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;-webkit-box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;" >
|
||||
</a>
|
||||
</p>
|
||||
|
||||
- [About](#about)
|
||||
@@ -158,7 +163,7 @@ To compile the project, you'll need:
|
||||
Then you can compile the server (and the migration tool if you want):
|
||||
|
||||
```shell
|
||||
cargo build --release -p lldap -p migration-tool
|
||||
cargo build --release -p lldap -p lldap_migration_tool
|
||||
```
|
||||
|
||||
The resulting binaries will be in `./target/release/`. Alternatively, you can
|
||||
@@ -257,6 +262,7 @@ folder for help with:
|
||||
- [Dex](example_configs/dex_config.yml)
|
||||
- [Dokuwiki](example_configs/dokuwiki.md)
|
||||
- [Dolibarr](example_configs/dolibarr.md)
|
||||
- [Ejabberd](example_configs/ejabberd.md)
|
||||
- [Emby](example_configs/emby.md)
|
||||
- [Gitea](example_configs/gitea.md)
|
||||
- [Grafana](example_configs/grafana_ldap_config.toml)
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
[package]
|
||||
name = "lldap_app"
|
||||
version = "0.4.3"
|
||||
authors = ["Valentin Tolmer <valentin@tolmer.fr>"]
|
||||
description = "Frontend for LLDAP"
|
||||
edition = "2021"
|
||||
homepage = "https://github.com/lldap/lldap"
|
||||
license = "GPL-3.0-only"
|
||||
name = "lldap_app"
|
||||
repository = "https://github.com/lldap/lldap"
|
||||
version = "0.5.0-alpha"
|
||||
include = ["src/**/*", "queries/**/*", "Cargo.toml", "../schema.graphql"]
|
||||
|
||||
[dependencies]
|
||||
@@ -10,7 +14,7 @@ anyhow = "1"
|
||||
base64 = "0.13"
|
||||
gloo-console = "0.2.3"
|
||||
gloo-file = "0.2.3"
|
||||
gloo-net = "*"
|
||||
gloo-net = "0.2"
|
||||
graphql_client = "0.10"
|
||||
http = "0.2"
|
||||
jwt = "0.13"
|
||||
@@ -19,9 +23,9 @@ serde = "1"
|
||||
serde_json = "1"
|
||||
url-escape = "0.1.1"
|
||||
validator = "=0.14"
|
||||
validator_derive = "*"
|
||||
validator_derive = "0.16"
|
||||
wasm-bindgen = "0.2"
|
||||
wasm-bindgen-futures = "*"
|
||||
wasm-bindgen-futures = "0.4"
|
||||
yew = "0.19.3"
|
||||
yew-router = "0.16"
|
||||
|
||||
@@ -43,13 +47,13 @@ features = [
|
||||
]
|
||||
|
||||
[dependencies.chrono]
|
||||
version = "*"
|
||||
version = "0.4"
|
||||
features = [
|
||||
"wasmbind"
|
||||
]
|
||||
|
||||
[dependencies.lldap_auth]
|
||||
path = "../auth"
|
||||
version = "0.3"
|
||||
features = [ "opaque_client" ]
|
||||
|
||||
[dependencies.image]
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
[package]
|
||||
name = "lldap_auth"
|
||||
version = "0.3.0"
|
||||
authors = ["Valentin Tolmer <valentin@tolmer.fr>"]
|
||||
description = "Authentication protocol for LLDAP"
|
||||
edition = "2021"
|
||||
homepage = "https://github.com/lldap/lldap"
|
||||
license = "GPL-3.0-only"
|
||||
name = "lldap_auth"
|
||||
repository = "https://github.com/lldap/lldap"
|
||||
version = "0.3.0"
|
||||
|
||||
[features]
|
||||
default = ["opaque_server", "opaque_client"]
|
||||
@@ -14,17 +18,17 @@ js = []
|
||||
rust-argon2 = "0.8"
|
||||
curve25519-dalek = "3"
|
||||
digest = "0.9"
|
||||
generic-array = "*"
|
||||
generic-array = "0.14"
|
||||
rand = "0.8"
|
||||
serde = "*"
|
||||
serde = "1"
|
||||
sha2 = "0.9"
|
||||
thiserror = "*"
|
||||
thiserror = "1"
|
||||
|
||||
[dependencies.opaque-ke]
|
||||
version = "0.6"
|
||||
|
||||
[dependencies.chrono]
|
||||
version = "*"
|
||||
version = "0.4"
|
||||
features = [ "serde" ]
|
||||
|
||||
# For WASM targets, use the JS getrandom.
|
||||
|
||||
58
docs/migration_guides/v0.5.md
Normal file
58
docs/migration_guides/v0.5.md
Normal file
@@ -0,0 +1,58 @@
|
||||
# Migration from 0.4 to 0.5
|
||||
|
||||
Welcome! If you're here, it's probably that the migration from 0.4.x to 0.5
|
||||
didn't go smoothly for you. Don't worry, we can fix that.
|
||||
|
||||
## Multiple users with the same email
|
||||
|
||||
This is the most common case. You can see in the LLDAP logs that there are
|
||||
several users with the same email, and they are listed.
|
||||
|
||||
This is not allowed anymore in v0.5, to prevent a user from setting their email
|
||||
to someone else's email and gaining access to systems that identify by email.
|
||||
|
||||
The problem is that you currently have several users with the same email, so the
|
||||
constraint cannot be enforced.
|
||||
|
||||
### Step 1: Take a note of the users with duplicate emails
|
||||
|
||||
In the LLDAP logs when you tried to start v0.5+, you'll see some warnings with
|
||||
the list of users with the same emails. Take note of them.
|
||||
|
||||
### Step 2: Downgrade to v0.4.3
|
||||
|
||||
If using docker, switch to the `lldap/lldap:v0.4.3` image. Alternatively, grab
|
||||
the binaries at https://github.com/lldap/lldap/releases/tag/v0.4.3.
|
||||
|
||||
This downgrade is safe and supported.
|
||||
|
||||
### Step 3: Remove duplicate emails
|
||||
|
||||
Restart LLDAP with the v0.4.3 version, and using your notes from step 1, change
|
||||
the email of users with duplicate emails to make sure that each email is unique.
|
||||
|
||||
### Step 4: Upgrade again
|
||||
|
||||
You can now revert to the initial version.
|
||||
|
||||
## Multiple users/groups with the same UUID
|
||||
|
||||
This should be extremely rare. In this case, you'll need to find which users
|
||||
have the same UUID, revert to v0.4.3 to be able to apply the changes, and delete
|
||||
one of the duplicates.
|
||||
|
||||
## FAQ
|
||||
|
||||
### What if I want several users to be controlled by the same email?
|
||||
|
||||
You can use plus codes to set "the same" email to several users, while ensuring
|
||||
that they can't identify as each other. For instance:
|
||||
|
||||
- Admin: `admin@example.com`
|
||||
- Read-only admin: `admin+readonly@example.com`
|
||||
- Jellyfin admin: `admin+jellyfin@example.com`
|
||||
|
||||
### I'm upgrading to a higher version than v0.5.
|
||||
|
||||
This guide is still relevant: you can use whatever later version in place of
|
||||
v0.5. You'll still need to revert to v0.4.3 to apply the changes.
|
||||
30
example_configs/ejabberd.md
Normal file
30
example_configs/ejabberd.md
Normal file
@@ -0,0 +1,30 @@
|
||||
# Basic LDAP auth for a Ejabberd XMPP server
|
||||
|
||||
[Main documentation here.](https://docs.ejabberd.im/admin/configuration/ldap/)
|
||||
|
||||
For simple user auth add this to main ejabberd.yml:
|
||||
|
||||
```
|
||||
host_config:
|
||||
xmpp.example.org:
|
||||
auth_method: [ldap]
|
||||
ldap_servers:
|
||||
- 127.0.0.1 #IP or hostname of LLDAP server
|
||||
ldap_port: 3890
|
||||
ldap_uids:
|
||||
- uid
|
||||
ldap_rootdn: "uid=lldap_readonly,ou=people,dc=example,dc=org"
|
||||
ldap_password: "secret"
|
||||
ldap_base: "ou=people,dc=example,dc=org"
|
||||
```
|
||||
|
||||
## vCard from LDAP
|
||||
Theoretically possible, [see the documentation.](https://docs.ejabberd.im/admin/configuration/ldap/#vcard-in-ldap)
|
||||
|
||||
TODO
|
||||
|
||||
## Shared roster groups from LDAP
|
||||
|
||||
Theoretically possible, [see the documentation.](https://docs.ejabberd.im/admin/configuration/ldap/#shared-roster-in-ldap)
|
||||
|
||||
TODO
|
||||
@@ -44,6 +44,6 @@ username = "uid"
|
||||
# If you want to map your ldap groups to grafana's groups, see: https://grafana.com/docs/grafana/latest/auth/ldap/#group-mappings
|
||||
# As a quick example, here is how you would map lldap's admin group to grafana's admin
|
||||
# [[servers.group_mappings]]
|
||||
# group_dn = "uid=lldap_admin,ou=groups,dc=example,dc=org"
|
||||
# group_dn = "cn=lldap_admin,ou=groups,dc=example,dc=org"
|
||||
# org_role = "Admin"
|
||||
# grafana_admin = true
|
||||
|
||||
@@ -7,6 +7,7 @@ Home Assistant configures ldap auth via the [Command Line Auth Provider](https:/
|
||||
The [auth script](lldap-ha-auth.sh) attempts to authenticate a user against an LLDAP server, using credentials provided via `username` and `password` environment variables. The first argument must be the URL of your LLDAP server, accessible from Home Assistant. You can provide an additional optional argument to confine allowed logins to a single group. The script will output the user's display name as the `name` variable, if not empty.
|
||||
|
||||
1. Copy the [auth script](lldap-ha-auth.sh) to your home assistant instance. In this example, we use `/config/lldap-auth.sh`.
|
||||
- Set the script as executable by running `chmod +x /config/lldap-auth-sh`
|
||||
2. Add the following to your configuration.yaml in Home assistant:
|
||||
```yaml
|
||||
homeassistant:
|
||||
@@ -20,4 +21,4 @@ homeassistant:
|
||||
args: ["https://lldap.example.com", "homeassistant_user"]
|
||||
meta: true
|
||||
```
|
||||
3. Reload your config or restart Home Assistant
|
||||
3. Reload your config or restart Home Assistant
|
||||
|
||||
113
example_configs/opnsense.md
Normal file
113
example_configs/opnsense.md
Normal file
@@ -0,0 +1,113 @@
|
||||
# Configuration for OPNsense
|
||||
|
||||
## Create a LDAP Server
|
||||
|
||||
- Login to OPNsense
|
||||
- Navigate to: `System > Access > Servers`
|
||||
- Create a new server by clicking on the `+` icon
|
||||
|
||||
## Server Config
|
||||
|
||||
- Descriptive Name: `A Descriptive Name`
|
||||
- Type: `LDAP`
|
||||
- Hostname or IP address: `Hostname or IP for your LLDAP host`
|
||||
- Port value: `Your LLDAP port`
|
||||
- Default: `3890`
|
||||
- Transport: `TCP - Standard`
|
||||
- Protocol version: `3`
|
||||
|
||||
Make sure the host running LLDAP is accessible to OPNsense and that you mapped the LLDAP port to the LLDAP host.
|
||||
|
||||
## LDAP Config
|
||||
|
||||
### Bind credentials
|
||||
|
||||
#### User DN
|
||||
|
||||
```
|
||||
uid=admin,ou=people,dc=example,dc=com
|
||||
```
|
||||
|
||||
It is recommended that you create a separate user account (e.g, `bind_user`) instead of `admin` for sharing Bind credentials with other services. The `bind_user` should be a member of the `lldap_strict_readonly` group to limit access to your LDAP configuration in LLDAP.
|
||||
|
||||
#### Password
|
||||
|
||||
```
|
||||
xxx
|
||||
```
|
||||
|
||||
Enter the password that you set for the user specified in the User DN field.
|
||||
|
||||
### Search Scope
|
||||
|
||||
```
|
||||
One Level
|
||||
```
|
||||
|
||||
### Base DN
|
||||
|
||||
```
|
||||
dc=example,dc=com
|
||||
```
|
||||
|
||||
This is the same LDAP Base DN that you set via the *LLDAP_LDAP_BASE_DN* environment variable or in `lldap_config.toml`.
|
||||
|
||||
### Authentication containers
|
||||
|
||||
```
|
||||
ou=people,dc=example,dc=com
|
||||
```
|
||||
|
||||
Note: The `Select` box may not work for selecting containers. You can just enter the `Authentication containers` directly into the text field.
|
||||
|
||||
### Extended Query
|
||||
|
||||
```
|
||||
&(objectClass=person)(memberof=cn=lldap_admin,ou=groups,dc=example,dc=com)
|
||||
```
|
||||
|
||||
It is recommended that you create a unique LDAP group (e.g., `lldap_opnsense`) in LLDAP and use that group in this query instead of `lldap_admin`. This will limit OPNsense access to users in the `lldap_opnsense` group and make it easier to synchronize LLDAP groups with OPNsense groups for managing OPNsense access.
|
||||
|
||||
### Initial Template
|
||||
|
||||
```
|
||||
OpenLDAP
|
||||
```
|
||||
|
||||
### User naming attribute
|
||||
|
||||
```
|
||||
uid
|
||||
```
|
||||
|
||||
## Optional Configuration
|
||||
|
||||
The above configuration will connect OPNsense to LLDAP. This optional configuration will synchronize groups between LLDAP and OPNsense and automate user creation when an authorized LLDAP user logs into OPNsense.
|
||||
|
||||
### Remaining Server Configuration
|
||||
|
||||
Enable the following options on the OPNsense configuration page for your LLDAP server (the same page where you entered the prior configuration):
|
||||
|
||||
- Read Properties: `Checked`
|
||||
- Synchronize groups: `Checked`
|
||||
- Automatic user creation: `Checked`
|
||||
|
||||
### Create OPNsense Group
|
||||
|
||||
Go to `System > Access > Groups` and create a new group with the **same** name as the LLDAP group used to authenticate users for OPNsense.
|
||||
|
||||
By default, you would name your OPNsense group `lldap_admin` unless you followed the recommended advice in this guide and created a separate `lldap_opnsense` group for managing OPNsense users.
|
||||
|
||||
If you want your LLDAP users to have full administrator access in OPNsense, then you need to edit the `Assigned Privileges` for the group and add the `GUI - All pages` system privilege.
|
||||
|
||||
### Enable LLDAP as an Authentication Option
|
||||
|
||||
Go to `System > Settings > Administration` page and scroll down to the `Authentication` section. Add your LLDAP server configuration to the `Server` field.
|
||||
|
||||
## Testing LLDAP
|
||||
|
||||
OPNsense includes a built-in feature for testing user authentication at `System > Access > Tester`. Select your LLDAP server configuration in the `Authentication Server` to test logins for your LLDAP users.
|
||||
|
||||
## More Information
|
||||
|
||||
Please read the [OPNsense docs](https://docs.opnsense.org/manual/how-tos/user-ldap.html) for more information on LDAP configuration and managing access to OPNsense.
|
||||
117
example_configs/pfsense.md
Normal file
117
example_configs/pfsense.md
Normal file
@@ -0,0 +1,117 @@
|
||||
# Configuration for pfSense
|
||||
|
||||
## Create a LDAP Server
|
||||
|
||||
- Login to pfSense
|
||||
- Navigate to: `System > User Manager > Authentication Servers`
|
||||
- Create a new server by clicking on the `+ Add` button
|
||||
|
||||
## LDAP Server Settings
|
||||
|
||||
- Descriptive Name: `A Descriptive Name`
|
||||
- Type: `LDAP`
|
||||
- Hostname or IP address: `Hostname or IP for your LLDAP host`
|
||||
- Port value: `Your LLDAP port`
|
||||
- Transport: `TCP - Standard`
|
||||
- Protocol version: `3`
|
||||
- Server Timeout: `25`
|
||||
|
||||
(Make sure the host running LLDAP is accessible to pfSense and that you mapped the LLDAP port to the LLDAP host)
|
||||
### Search Scope
|
||||
```
|
||||
Entire Subtree
|
||||
```
|
||||
### Base DN
|
||||
|
||||
```
|
||||
dc=example,dc=com
|
||||
```
|
||||
|
||||
This is the same LDAP Base DN that you set via the *LLDAP_LDAP_BASE_DN* environment variable or in `lldap_config.toml`.
|
||||
### Authentication containers
|
||||
|
||||
```
|
||||
ou=people
|
||||
```
|
||||
|
||||
Note: The `Select a container` box may not work for selecting containers. You can just enter the `Authentication containers` directly into the text field.
|
||||
|
||||
### Extended Query
|
||||
|
||||
Enable extended query: `Checked`
|
||||
|
||||
### Query:
|
||||
|
||||
```
|
||||
&(objectClass=person)(|(memberof=cn=pfsense_admin,ou=groups,dc=example,dc=com)(memberof=cn=pfsense_guest,ou=groups,dc=example,dc=com))
|
||||
```
|
||||
|
||||
This example gives you two groups in LLDAP, one for pfSense admin access (`pfsense_admin`) and one for guest access (`pfsense_guest`). You **must** create these exact same groups in both LLDAP and pfSense, then give them the correct permissions in pfSense.
|
||||
|
||||
### Bind Anonymous
|
||||
`Unchecked`
|
||||
|
||||
### Bind credentials
|
||||
|
||||
#### User DN
|
||||
|
||||
```
|
||||
uid=yourbinduser,ou=people,dc=example,dc=com
|
||||
```
|
||||
|
||||
It is recommended that you create a separate read-only user account (e.g, `readonly`) instead of `admin` for sharing Bind credentials with other services. The `readonly` should be a member of the `lldap_strict_readonly` group to limit access to your LDAP configuration in LLDAP.
|
||||
|
||||
#### Password
|
||||
|
||||
```
|
||||
LLDAPPasswordForBindUser
|
||||
```
|
||||
|
||||
### User naming attribute
|
||||
```
|
||||
uid
|
||||
```
|
||||
### Group naming attribute
|
||||
```
|
||||
cn
|
||||
```
|
||||
### Group member attribute
|
||||
```
|
||||
memberof
|
||||
```
|
||||
### RFC 2307 Groups
|
||||
`Unchecked`
|
||||
|
||||
### Group Object Class
|
||||
`groupOfUniqueNames`
|
||||
|
||||
### Shell Authentication Group DN
|
||||
`cn=pfsense_admin,ou=groups,dc=example,dc=com`
|
||||
|
||||
(This is only if you want to give a group shell access through LDAP. Leave blank and only the pfSense admin user will have shell access.
|
||||
|
||||
### Remaining Server Configuration
|
||||
|
||||
Enable the following options on the pfSense configuration page for your LLDAP server (the same page where you entered the prior configuration):
|
||||
|
||||
- UTF8 Encodes: `Checked`
|
||||
- Username Alterations: `Unchecked`
|
||||
- Allow unauthenticated bind: `Unchecked`
|
||||
|
||||
### Create pfSense Groups
|
||||
|
||||
Go to `System > User Manager > Groups` and create a new group(s) with the **same exact** name as the LLDAP group(s) used to authenticate users for pfSense (`pfsense_admin` and `pfsense_guest` in this example).
|
||||
|
||||
If you want your LLDAP users to have full administrator access in pfSense, then you need to edit the `Assigned Privileges` for the group and add the `WebCfg - All pages` system privilege. If you do not give any permissions to a group, you will be able to log in but only see an empty webUI.
|
||||
|
||||
### Enable LLDAP as an Authentication Option
|
||||
|
||||
Go to `System > User Manager > Settings` page. Add your LLDAP server configuration to the `Authentication Server` field. **The "Save & Test" Button will fail the test results at step 3. No clue why.**
|
||||
|
||||
## Testing LLDAP
|
||||
|
||||
pfSense includes a built-in feature for testing user authentication at `Diagnostics > Authentication`. Select your LLDAP server configuration in the `Authentication Server` to test logins for your LLDAP users. The groups (only the ones you added to pfSense) should show up when tested.
|
||||
|
||||
## More Information
|
||||
|
||||
Please read the [pfSense docs](https://docs.netgate.com/pfsense/en/latest/usermanager/ldap.html) for more information on LDAP configuration and managing access to pfSense.
|
||||
@@ -13,6 +13,6 @@ You setup https://zend.to/ for using LDAP by editing `/opt/zendto/config/prefere
|
||||
'authLDAPUsernameAttr' => 'uid',
|
||||
'authLDAPEmailAttr' => 'mail',
|
||||
'authLDAPMemberKey' => 'memberOf',
|
||||
'authLDAPMemberRole' => 'uid=zendto,ou=groups,dc=example,dc=com',
|
||||
'authLDAPMemberRole' => 'cn=zendto,ou=groups,dc=example,dc=com',
|
||||
```
|
||||
Every user of the group `zendto` is allowed to login.
|
||||
|
||||
@@ -93,8 +93,17 @@ database_url = "sqlite:///data/users.db?mode=rwc"
|
||||
## would still have to perform an (expensive) brute force attack to find
|
||||
## each password.
|
||||
## Randomly generated on first run if it doesn't exist.
|
||||
## Alternatively, you can use key_seed to override this instead of relying on
|
||||
## a file.
|
||||
## Env variable: LLDAP_KEY_FILE
|
||||
key_file = "/data/private_key"
|
||||
|
||||
## Seed to generate the server private key, see key_file above.
|
||||
## This can be any random string, the recommendation is that it's at least 12
|
||||
## characters long.
|
||||
## Env variable: LLDAP_KEY_SEED
|
||||
#key_seed = "RanD0m STR1ng"
|
||||
|
||||
## Ignored attributes.
|
||||
## Some services will request attributes that are not present in LLDAP. When it
|
||||
## is the case, LLDAP will warn about the attribute being unknown. If you want
|
||||
@@ -106,7 +115,7 @@ key_file = "/data/private_key"
|
||||
## Options to configure SMTP parameters, to send password reset emails.
|
||||
## To set these options from environment variables, use the following format
|
||||
## (example with "password"): LLDAP_SMTP_OPTIONS__PASSWORD
|
||||
#[smtp_options]
|
||||
[smtp_options]
|
||||
## Whether to enabled password reset via email, from LLDAP.
|
||||
#enable_password_reset=true
|
||||
## The SMTP server.
|
||||
@@ -128,7 +137,7 @@ key_file = "/data/private_key"
|
||||
## Options to configure LDAPS.
|
||||
## To set these options from environment variables, use the following format
|
||||
## (example with "port"): LLDAP_LDAPS_OPTIONS__PORT
|
||||
#[ldaps_options]
|
||||
[ldaps_options]
|
||||
## Whether to enable LDAPS.
|
||||
#enabled=true
|
||||
## Port on which to listen.
|
||||
|
||||
@@ -1,20 +1,24 @@
|
||||
[package]
|
||||
name = "migration-tool"
|
||||
version = "0.4.2"
|
||||
edition = "2021"
|
||||
authors = ["Valentin Tolmer <valentin@tolmer.fr>"]
|
||||
description = "CLI migration tool to go from OpenLDAP to LLDAP"
|
||||
edition = "2021"
|
||||
homepage = "https://github.com/lldap/lldap"
|
||||
license = "GPL-3.0-only"
|
||||
name = "lldap_migration_tool"
|
||||
repository = "https://github.com/lldap/lldap"
|
||||
version = "0.4.2"
|
||||
|
||||
[dependencies]
|
||||
anyhow = "*"
|
||||
anyhow = "1"
|
||||
base64 = "0.13"
|
||||
rand = "0.8"
|
||||
requestty = "0.4.1"
|
||||
serde = "1"
|
||||
serde_json = "1"
|
||||
smallvec = "*"
|
||||
smallvec = "1"
|
||||
|
||||
[dependencies.lldap_auth]
|
||||
path = "../auth"
|
||||
version = "0.3"
|
||||
features = ["opaque_client"]
|
||||
|
||||
[dependencies.graphql_client]
|
||||
@@ -23,11 +27,11 @@ default-features = false
|
||||
version = "0.11"
|
||||
|
||||
[dependencies.reqwest]
|
||||
version = "*"
|
||||
version = "0.11"
|
||||
default-features = false
|
||||
features = ["json", "blocking", "rustls-tls"]
|
||||
|
||||
[dependencies.ldap3]
|
||||
version = "*"
|
||||
version = "0.11"
|
||||
default-features = false
|
||||
features = ["sync", "tls-rustls"]
|
||||
|
||||
@@ -1,8 +1,14 @@
|
||||
[package]
|
||||
authors = ["Valentin Tolmer <valentin@tolmer.fr>"]
|
||||
categories = ["authentication", "command-line-utilities"]
|
||||
description = "Super-simple and lightweight LDAP server"
|
||||
edition = "2021"
|
||||
homepage = "https://github.com/lldap/lldap"
|
||||
keywords = ["cli", "ldap", "graphql", "server", "authentication"]
|
||||
license = "GPL-3.0-only"
|
||||
name = "lldap"
|
||||
version = "0.4.3"
|
||||
repository = "https://github.com/lldap/lldap"
|
||||
version = "0.5.0-alpha"
|
||||
|
||||
[dependencies]
|
||||
actix = "0.13"
|
||||
@@ -13,44 +19,45 @@ actix-server = "2"
|
||||
actix-service = "2"
|
||||
actix-web = "4.3"
|
||||
actix-web-httpauth = "0.8"
|
||||
anyhow = "*"
|
||||
anyhow = "1"
|
||||
async-trait = "0.1"
|
||||
base64 = "0.21"
|
||||
bincode = "1.3"
|
||||
cron = "*"
|
||||
cron = "0.12"
|
||||
derive_builder = "0.12"
|
||||
figment_file_provider_adapter = "0.1"
|
||||
futures = "*"
|
||||
futures-util = "*"
|
||||
futures = "0.3"
|
||||
futures-util = "0.3"
|
||||
hmac = "0.12"
|
||||
http = "*"
|
||||
http = "0.2"
|
||||
itertools = "0.10"
|
||||
juniper = "0.15"
|
||||
jwt = "0.16"
|
||||
lber = "0.4.1"
|
||||
ldap3_proto = ">=0.3.1"
|
||||
log = "*"
|
||||
log = "0.4"
|
||||
orion = "0.17"
|
||||
rand_chacha = "0.3"
|
||||
rustls-pemfile = "1"
|
||||
serde = "*"
|
||||
serde = "1"
|
||||
serde_bytes = "0.11"
|
||||
serde_json = "1"
|
||||
sha2 = "0.10"
|
||||
thiserror = "*"
|
||||
thiserror = "1"
|
||||
time = "0.3"
|
||||
tokio-rustls = "0.23"
|
||||
tokio-stream = "*"
|
||||
tokio-stream = "0.1"
|
||||
tokio-util = "0.7"
|
||||
tracing = "*"
|
||||
tracing = "0.1"
|
||||
tracing-actix-web = "0.7"
|
||||
tracing-attributes = "^0.1.21"
|
||||
tracing-log = "*"
|
||||
tracing-log = "0.1"
|
||||
urlencoding = "2"
|
||||
webpki-roots = "*"
|
||||
webpki-roots = "0.23"
|
||||
|
||||
[dependencies.chrono]
|
||||
features = ["serde"]
|
||||
version = "*"
|
||||
version = "0.4"
|
||||
|
||||
[dependencies.clap]
|
||||
features = ["std", "color", "suggestions", "derive", "env"]
|
||||
@@ -58,7 +65,7 @@ version = "4"
|
||||
|
||||
[dependencies.figment]
|
||||
features = ["env", "toml"]
|
||||
version = "*"
|
||||
version = "0.10"
|
||||
|
||||
[dependencies.tracing-subscriber]
|
||||
version = "0.3"
|
||||
@@ -70,7 +77,7 @@ default-features = false
|
||||
version = "0.10.1"
|
||||
|
||||
[dependencies.lldap_auth]
|
||||
path = "../auth"
|
||||
version = "0.3"
|
||||
|
||||
[dependencies.opaque-ke]
|
||||
version = "0.6"
|
||||
@@ -81,7 +88,7 @@ version = "0.8"
|
||||
|
||||
[dependencies.secstr]
|
||||
features = ["serde"]
|
||||
version = "*"
|
||||
version = "0.5"
|
||||
|
||||
[dependencies.tokio]
|
||||
features = ["full"]
|
||||
@@ -89,7 +96,7 @@ version = "1.25"
|
||||
|
||||
[dependencies.uuid]
|
||||
features = ["v3"]
|
||||
version = "*"
|
||||
version = "1"
|
||||
|
||||
[dependencies.tracing-forest]
|
||||
features = ["smallvec", "chrono", "tokio"]
|
||||
@@ -119,4 +126,30 @@ version = "0.20"
|
||||
features = ["dangerous_configuration"]
|
||||
|
||||
[dev-dependencies]
|
||||
assert_cmd = "2.0"
|
||||
mockall = "0.11"
|
||||
nix = "0.26.2"
|
||||
|
||||
[dev-dependencies.graphql_client]
|
||||
features = ["graphql_query_derive", "reqwest-rustls"]
|
||||
default-features = false
|
||||
version = "0.11"
|
||||
|
||||
[dev-dependencies.ldap3]
|
||||
version = "0.11"
|
||||
default-features = false
|
||||
features = ["sync", "tls-rustls"]
|
||||
|
||||
[dev-dependencies.reqwest]
|
||||
version = "0.11"
|
||||
default-features = false
|
||||
features = ["json", "blocking", "rustls-tls"]
|
||||
|
||||
[dev-dependencies.serial_test]
|
||||
version = "2.0.0"
|
||||
default-features = false
|
||||
features = ["file_locks"]
|
||||
|
||||
[dev-dependencies.uuid]
|
||||
version = "1"
|
||||
features = ["v4"]
|
||||
|
||||
@@ -86,7 +86,7 @@ pub mod tests {
|
||||
handler
|
||||
.create_user(CreateUserRequest {
|
||||
user_id: UserId::new(name),
|
||||
email: "bob@bob.bob".to_string(),
|
||||
email: format!("{}@bob.bob", name),
|
||||
display_name: Some("display ".to_string() + name),
|
||||
first_name: Some("first ".to_string() + name),
|
||||
last_name: Some("last ".to_string() + name),
|
||||
|
||||
@@ -2,15 +2,17 @@ use crate::domain::{
|
||||
sql_tables::{DbConnection, SchemaVersion},
|
||||
types::{GroupId, UserId, Uuid},
|
||||
};
|
||||
use anyhow::Context;
|
||||
use itertools::Itertools;
|
||||
use sea_orm::{
|
||||
sea_query::{self, ColumnDef, Expr, ForeignKey, ForeignKeyAction, Query, Table, Value},
|
||||
ConnectionTrait, FromQueryResult, Iden, Statement, TransactionTrait,
|
||||
sea_query::{
|
||||
self, all, ColumnDef, Expr, ForeignKey, ForeignKeyAction, Func, Index, Query, Table, Value,
|
||||
},
|
||||
ConnectionTrait, FromQueryResult, Iden, Order, Statement, TransactionTrait,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tracing::{info, instrument, warn};
|
||||
|
||||
use super::sql_tables::LAST_SCHEMA_VERSION;
|
||||
|
||||
#[derive(Iden, PartialEq, Eq, Debug, Serialize, Deserialize, Clone, Copy)]
|
||||
pub enum Users {
|
||||
Table,
|
||||
@@ -460,30 +462,136 @@ async fn migrate_to_v3(pool: &DbConnection) -> anyhow::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn migrate_to_v4(pool: &DbConnection) -> anyhow::Result<()> {
|
||||
let builder = pool.get_database_backend();
|
||||
// Make emails and UUIDs unique.
|
||||
if let Err(e) = pool
|
||||
.execute(
|
||||
builder.build(
|
||||
Index::create()
|
||||
.if_not_exists()
|
||||
.name("unique-user-email")
|
||||
.table(Users::Table)
|
||||
.col(Users::Email)
|
||||
.unique(),
|
||||
),
|
||||
)
|
||||
.await
|
||||
.context(
|
||||
r#"while enforcing unicity on emails (2 users have the same email).
|
||||
|
||||
See https://github.com/lldap/lldap/blob/main/docs/migration_guides/v0.5.md for details.
|
||||
|
||||
"#,
|
||||
)
|
||||
{
|
||||
warn!("Found several users with the same email:");
|
||||
for (email, users) in &pool
|
||||
.query_all(
|
||||
builder.build(
|
||||
Query::select()
|
||||
.from(Users::Table)
|
||||
.columns([Users::Email, Users::UserId])
|
||||
.order_by_columns([(Users::Email, Order::Asc), (Users::UserId, Order::Asc)])
|
||||
.and_where(
|
||||
Expr::col(Users::Email).in_subquery(
|
||||
Query::select()
|
||||
.from(Users::Table)
|
||||
.column(Users::Email)
|
||||
.group_by_col(Users::Email)
|
||||
.cond_having(all![Expr::gt(
|
||||
Expr::expr(Func::count(Expr::col(Users::Email))),
|
||||
1
|
||||
)])
|
||||
.take(),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
.await
|
||||
.expect("Could not check duplicate users")
|
||||
.into_iter()
|
||||
.map(|row| {
|
||||
(
|
||||
row.try_get::<UserId>("", &Users::UserId.to_string())
|
||||
.unwrap(),
|
||||
row.try_get::<String>("", &Users::Email.to_string())
|
||||
.unwrap(),
|
||||
)
|
||||
})
|
||||
.group_by(|(_user, email)| email.to_owned())
|
||||
{
|
||||
warn!("Email: {email}");
|
||||
for (user, _email) in users {
|
||||
warn!(" User: {}", user.as_str());
|
||||
}
|
||||
}
|
||||
return Err(e);
|
||||
}
|
||||
pool.execute(
|
||||
builder.build(
|
||||
Index::create()
|
||||
.if_not_exists()
|
||||
.name("unique-user-uuid")
|
||||
.table(Users::Table)
|
||||
.col(Users::Uuid)
|
||||
.unique(),
|
||||
),
|
||||
)
|
||||
.await
|
||||
.context("while enforcing unicity on user UUIDs (2 users have the same UUID)")?;
|
||||
pool.execute(
|
||||
builder.build(
|
||||
Index::create()
|
||||
.if_not_exists()
|
||||
.name("unique-group-uuid")
|
||||
.table(Groups::Table)
|
||||
.col(Groups::Uuid)
|
||||
.unique(),
|
||||
),
|
||||
)
|
||||
.await
|
||||
.context("while enforcing unicity on group UUIDs (2 groups have the same UUID)")?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// This is needed to make an array of async functions.
|
||||
macro_rules! to_sync {
|
||||
($l:ident) => {
|
||||
|pool| -> std::pin::Pin<Box<dyn std::future::Future<Output = anyhow::Result<()>>>> {
|
||||
Box::pin($l(pool))
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub async fn migrate_from_version(
|
||||
pool: &DbConnection,
|
||||
version: SchemaVersion,
|
||||
last_version: SchemaVersion,
|
||||
) -> anyhow::Result<()> {
|
||||
match version.cmp(&LAST_SCHEMA_VERSION) {
|
||||
std::cmp::Ordering::Less => info!(
|
||||
"Upgrading DB schema from {} to {}",
|
||||
version.0, LAST_SCHEMA_VERSION.0
|
||||
),
|
||||
match version.cmp(&last_version) {
|
||||
std::cmp::Ordering::Less => (),
|
||||
std::cmp::Ordering::Equal => return Ok(()),
|
||||
std::cmp::Ordering::Greater => anyhow::bail!("DB version downgrading is not supported"),
|
||||
}
|
||||
if version < SchemaVersion(2) {
|
||||
migrate_to_v2(pool).await?;
|
||||
}
|
||||
if version < SchemaVersion(3) {
|
||||
migrate_to_v3(pool).await?;
|
||||
info!("Upgrading DB schema from version {}", version.0);
|
||||
let migrations = [
|
||||
to_sync!(migrate_to_v2),
|
||||
to_sync!(migrate_to_v3),
|
||||
to_sync!(migrate_to_v4),
|
||||
];
|
||||
for migration in 2..=4 {
|
||||
if version < SchemaVersion(migration) && SchemaVersion(migration) <= last_version {
|
||||
info!("Upgrading DB schema to version {}", migration);
|
||||
migrations[(migration - 2) as usize](pool).await?;
|
||||
}
|
||||
}
|
||||
let builder = pool.get_database_backend();
|
||||
pool.execute(
|
||||
builder.build(
|
||||
Query::update()
|
||||
.table(Metadata::Table)
|
||||
.value(Metadata::Version, Value::from(LAST_SCHEMA_VERSION)),
|
||||
.value(Metadata::Version, Value::from(last_version)),
|
||||
),
|
||||
)
|
||||
.await?;
|
||||
|
||||
@@ -21,7 +21,7 @@ impl From<SchemaVersion> for Value {
|
||||
}
|
||||
}
|
||||
|
||||
pub const LAST_SCHEMA_VERSION: SchemaVersion = SchemaVersion(3);
|
||||
const LAST_SCHEMA_VERSION: SchemaVersion = SchemaVersion(4);
|
||||
|
||||
pub async fn init_table(pool: &DbConnection) -> anyhow::Result<()> {
|
||||
let version = {
|
||||
@@ -32,7 +32,7 @@ pub async fn init_table(pool: &DbConnection) -> anyhow::Result<()> {
|
||||
SchemaVersion(1)
|
||||
}
|
||||
};
|
||||
migrate_from_version(pool, version).await?;
|
||||
migrate_from_version(pool, version, LAST_SCHEMA_VERSION).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -46,6 +46,7 @@ mod tests {
|
||||
use super::*;
|
||||
use chrono::prelude::*;
|
||||
use sea_orm::{ConnectionTrait, Database, DbBackend, FromQueryResult};
|
||||
use tracing::error;
|
||||
|
||||
async fn get_in_memory_db() -> DbConnection {
|
||||
let mut sql_opt = sea_orm::ConnectOptions::new("sqlite::memory:".to_owned());
|
||||
@@ -100,21 +101,21 @@ mod tests {
|
||||
let sql_pool = get_in_memory_db().await;
|
||||
sql_pool
|
||||
.execute(raw_statement(
|
||||
r#"CREATE TABLE users ( user_id TEXT, display_name TEXT, first_name TEXT NOT NULL, last_name TEXT, avatar BLOB, creation_date TEXT);"#,
|
||||
r#"CREATE TABLE users ( user_id TEXT, display_name TEXT, first_name TEXT NOT NULL, last_name TEXT, avatar BLOB, creation_date TEXT, email TEXT);"#,
|
||||
))
|
||||
.await
|
||||
.unwrap();
|
||||
sql_pool
|
||||
.execute(raw_statement(
|
||||
r#"INSERT INTO users (user_id, display_name, first_name, creation_date)
|
||||
VALUES ("bôb", "", "", "1970-01-01 00:00:00")"#,
|
||||
r#"INSERT INTO users (user_id, display_name, first_name, creation_date, email)
|
||||
VALUES ("bôb", "", "", "1970-01-01 00:00:00", "bob@bob.com")"#,
|
||||
))
|
||||
.await
|
||||
.unwrap();
|
||||
sql_pool
|
||||
.execute(raw_statement(
|
||||
r#"INSERT INTO users (user_id, display_name, first_name, creation_date)
|
||||
VALUES ("john", "John Doe", "John", "1971-01-01 00:00:00")"#,
|
||||
r#"INSERT INTO users (user_id, display_name, first_name, creation_date, email)
|
||||
VALUES ("john", "John Doe", "John", "1971-01-01 00:00:00", "bob2@bob.com")"#,
|
||||
))
|
||||
.await
|
||||
.unwrap();
|
||||
@@ -206,6 +207,69 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_migration_to_v4() {
|
||||
crate::infra::logging::init_for_tests();
|
||||
let sql_pool = get_in_memory_db().await;
|
||||
upgrade_to_v1(&sql_pool).await.unwrap();
|
||||
migrate_from_version(&sql_pool, SchemaVersion(1), SchemaVersion(3))
|
||||
.await
|
||||
.unwrap();
|
||||
sql_pool
|
||||
.execute(raw_statement(
|
||||
r#"INSERT INTO users (user_id, email, display_name, first_name, creation_date, uuid)
|
||||
VALUES ("bob", "bob@bob.com", "", "", "1970-01-01 00:00:00", "a02eaf13-48a7-30f6-a3d4-040ff7c52b04")"#,
|
||||
))
|
||||
.await
|
||||
.unwrap();
|
||||
sql_pool
|
||||
.execute(raw_statement(
|
||||
r#"INSERT INTO users (user_id, email, display_name, first_name, creation_date, uuid)
|
||||
VALUES ("bob2", "bob@bob.com", "", "", "1970-01-01 00:00:00", "986765a5-3f03-389e-b47b-536b2d6e1bec")"#,
|
||||
))
|
||||
.await
|
||||
.unwrap();
|
||||
error!(
|
||||
"{}",
|
||||
migrate_from_version(&sql_pool, SchemaVersion(3), SchemaVersion(4))
|
||||
.await
|
||||
.expect_err("migration should fail")
|
||||
);
|
||||
assert_eq!(
|
||||
sql_migrations::JustSchemaVersion::find_by_statement(raw_statement(
|
||||
r#"SELECT version FROM metadata"#
|
||||
))
|
||||
.one(&sql_pool)
|
||||
.await
|
||||
.unwrap()
|
||||
.unwrap(),
|
||||
sql_migrations::JustSchemaVersion {
|
||||
version: SchemaVersion(3)
|
||||
}
|
||||
);
|
||||
sql_pool
|
||||
.execute(raw_statement(
|
||||
r#"UPDATE users SET email = "new@bob.com" WHERE user_id = "bob2""#,
|
||||
))
|
||||
.await
|
||||
.unwrap();
|
||||
migrate_from_version(&sql_pool, SchemaVersion(3), SchemaVersion(4))
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
sql_migrations::JustSchemaVersion::find_by_statement(raw_statement(
|
||||
r#"SELECT version FROM metadata"#
|
||||
))
|
||||
.one(&sql_pool)
|
||||
.await
|
||||
.unwrap()
|
||||
.unwrap(),
|
||||
sql_migrations::JustSchemaVersion {
|
||||
version: SchemaVersion(4)
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_too_high_version() {
|
||||
let sql_pool = get_in_memory_db().await;
|
||||
|
||||
@@ -54,9 +54,16 @@ pub struct RunOpts {
|
||||
|
||||
/// Path to the file that contains the private server key.
|
||||
/// It will be created if it doesn't exist.
|
||||
/// Alternatively, you can set `server_key_seed`. If `server_key_seed` is given,
|
||||
/// `server_key_file` will be ignored.
|
||||
#[clap(long, env = "LLDAP_SERVER_KEY_FILE")]
|
||||
pub server_key_file: Option<String>,
|
||||
|
||||
/// Seed used to generate the private server key.
|
||||
/// Takes precedence over `server_key_file`.
|
||||
#[clap(long, env = "LLDAP_SERVER_KEY_SEED")]
|
||||
pub server_key_seed: Option<String>,
|
||||
|
||||
/// Change ldap host. Default: "0.0.0.0"
|
||||
#[clap(long, env = "LLDAP_LDAP_HOST")]
|
||||
pub ldap_host: Option<String>,
|
||||
|
||||
@@ -17,7 +17,7 @@ use serde::{Deserialize, Serialize};
|
||||
pub struct MailOptions {
|
||||
#[builder(default = "false")]
|
||||
pub enable_password_reset: bool,
|
||||
#[builder(default = "None")]
|
||||
#[builder(default)]
|
||||
pub from: Option<Mailbox>,
|
||||
#[builder(default = "None")]
|
||||
pub reply_to: Option<Mailbox>,
|
||||
@@ -25,7 +25,7 @@ pub struct MailOptions {
|
||||
pub server: String,
|
||||
#[builder(default = "587")]
|
||||
pub port: u16,
|
||||
#[builder(default = r#"String::default()"#)]
|
||||
#[builder(default)]
|
||||
pub user: String,
|
||||
#[builder(default = r#"SecUtf8::from("")"#)]
|
||||
pub password: SecUtf8,
|
||||
@@ -78,7 +78,7 @@ pub struct Configuration {
|
||||
pub ldap_base_dn: String,
|
||||
#[builder(default = r#"UserId::new("admin")"#)]
|
||||
pub ldap_user_dn: UserId,
|
||||
#[builder(default = r#"String::default()"#)]
|
||||
#[builder(default)]
|
||||
pub ldap_user_email: String,
|
||||
#[builder(default = r#"SecUtf8::from("password")"#)]
|
||||
pub ldap_user_pass: SecUtf8,
|
||||
@@ -92,6 +92,10 @@ pub struct Configuration {
|
||||
pub verbose: bool,
|
||||
#[builder(default = r#"String::from("server_key")"#)]
|
||||
pub key_file: String,
|
||||
// We want an Option to see whether there is a value or not, since the value is printed as
|
||||
// "***SECRET***".
|
||||
#[builder(default)]
|
||||
pub key_seed: Option<SecUtf8>,
|
||||
#[builder(default)]
|
||||
pub smtp_options: MailOptions,
|
||||
#[builder(default)]
|
||||
@@ -111,7 +115,14 @@ impl std::default::Default for Configuration {
|
||||
|
||||
impl ConfigurationBuilder {
|
||||
pub fn build(self) -> Result<Configuration> {
|
||||
let server_setup = get_server_setup(self.key_file.as_deref().unwrap_or("server_key"))?;
|
||||
let server_setup = get_server_setup(
|
||||
self.key_file.as_deref().unwrap_or("server_key"),
|
||||
self.key_seed
|
||||
.as_ref()
|
||||
.and_then(|o| o.as_ref())
|
||||
.map(SecUtf8::unsecure)
|
||||
.unwrap_or_default(),
|
||||
)?;
|
||||
Ok(self.server_setup(Some(server_setup)).private_build()?)
|
||||
}
|
||||
|
||||
@@ -154,10 +165,25 @@ fn write_to_readonly_file(path: &std::path::Path, buffer: &[u8]) -> Result<()> {
|
||||
Ok(file.write_all(buffer)?)
|
||||
}
|
||||
|
||||
fn get_server_setup(file_path: &str) -> Result<ServerSetup> {
|
||||
fn get_server_setup(file_path: &str, key_seed: &str) -> Result<ServerSetup> {
|
||||
use std::fs::read;
|
||||
let path = std::path::Path::new(file_path);
|
||||
if path.exists() {
|
||||
if !key_seed.is_empty() {
|
||||
if file_path != "server_key" || path.exists() {
|
||||
eprintln!("WARNING: A key_seed was given, we will ignore the server_key and generate one from the seed!");
|
||||
} else {
|
||||
println!("Got a key_seed, ignoring key_file");
|
||||
}
|
||||
let hash = |val: &[u8]| -> [u8; 32] {
|
||||
use sha2::{Digest, Sha256};
|
||||
let mut seed_hasher = Sha256::new();
|
||||
seed_hasher.update(val);
|
||||
seed_hasher.finalize().into()
|
||||
};
|
||||
use rand::SeedableRng;
|
||||
let mut rng = rand_chacha::ChaCha20Rng::from_seed(hash(key_seed.as_bytes()));
|
||||
Ok(ServerSetup::new(&mut rng))
|
||||
} else if path.exists() {
|
||||
let bytes = read(file_path).context(format!("Could not read key file `{}`", file_path))?;
|
||||
Ok(ServerSetup::deserialize(&bytes)?)
|
||||
} else {
|
||||
@@ -198,6 +224,10 @@ impl ConfigOverrider for RunOpts {
|
||||
config.key_file = path.to_string();
|
||||
}
|
||||
|
||||
if let Some(seed) = self.server_key_seed.as_ref() {
|
||||
config.key_seed = Some(SecUtf8::from(seed));
|
||||
}
|
||||
|
||||
if let Some(port) = self.ldap_port {
|
||||
config.ldap_port = port;
|
||||
}
|
||||
@@ -306,7 +336,14 @@ where
|
||||
if config.verbose {
|
||||
println!("Configuration: {:#?}", &config);
|
||||
}
|
||||
config.server_setup = Some(get_server_setup(&config.key_file)?);
|
||||
config.server_setup = Some(get_server_setup(
|
||||
&config.key_file,
|
||||
config
|
||||
.key_seed
|
||||
.as_ref()
|
||||
.map(SecUtf8::unsecure)
|
||||
.unwrap_or_default(),
|
||||
)?);
|
||||
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.");
|
||||
}
|
||||
@@ -318,3 +355,29 @@ where
|
||||
}
|
||||
Ok(config)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn check_generated_server_key() {
|
||||
assert_eq!(
|
||||
bincode::serialize(&get_server_setup("/doesnt/exist", "key seed").unwrap()).unwrap(),
|
||||
[
|
||||
255, 206, 202, 50, 247, 13, 59, 191, 69, 244, 148, 187, 150, 227, 12, 250, 20, 207,
|
||||
211, 151, 147, 33, 107, 132, 2, 252, 121, 94, 97, 6, 97, 232, 163, 168, 86, 246,
|
||||
249, 186, 31, 204, 59, 75, 65, 134, 108, 159, 15, 70, 246, 250, 150, 195, 54, 197,
|
||||
195, 176, 150, 200, 157, 119, 13, 173, 119, 8, 32, 0, 0, 0, 0, 0, 0, 0, 248, 123,
|
||||
35, 91, 194, 51, 52, 57, 191, 210, 68, 227, 107, 166, 232, 37, 195, 244, 100, 84,
|
||||
88, 212, 190, 12, 195, 57, 83, 72, 127, 189, 179, 16, 32, 0, 0, 0, 0, 0, 0, 0, 128,
|
||||
112, 60, 207, 205, 69, 67, 73, 24, 175, 187, 62, 16, 45, 59, 136, 78, 40, 187, 54,
|
||||
159, 94, 116, 33, 133, 119, 231, 43, 199, 164, 141, 7, 32, 0, 0, 0, 0, 0, 0, 0,
|
||||
212, 134, 53, 203, 131, 24, 138, 211, 162, 28, 23, 233, 251, 82, 34, 66, 98, 12,
|
||||
249, 205, 35, 208, 241, 50, 128, 131, 46, 189, 211, 51, 56, 109, 32, 0, 0, 0, 0, 0,
|
||||
0, 0, 84, 20, 147, 25, 50, 5, 243, 203, 216, 180, 175, 121, 159, 96, 123, 183, 146,
|
||||
251, 22, 44, 98, 168, 67, 224, 255, 139, 159, 25, 24, 254, 88, 3
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
27
server/tests/common/auth.rs
Normal file
27
server/tests/common/auth.rs
Normal file
@@ -0,0 +1,27 @@
|
||||
use crate::common::env;
|
||||
use reqwest::blocking::Client;
|
||||
|
||||
pub fn get_token(client: &Client) -> String {
|
||||
let username = env::admin_dn();
|
||||
let password = env::admin_password();
|
||||
let base_url = env::http_url();
|
||||
let response = client
|
||||
.post(format!("{base_url}/auth/simple/login"))
|
||||
.header(reqwest::header::CONTENT_TYPE, "application/json")
|
||||
.body(
|
||||
serde_json::to_string(&lldap_auth::login::ClientSimpleLoginRequest {
|
||||
username,
|
||||
password,
|
||||
})
|
||||
.expect("Failed to encode the username/password as json to log in"),
|
||||
)
|
||||
.send()
|
||||
.expect("Failed to send auth request")
|
||||
.error_for_status()
|
||||
.expect("Auth attempt failed");
|
||||
serde_json::from_str::<lldap_auth::login::ServerLoginResponse>(
|
||||
&response.text().expect("Failed to get response text"),
|
||||
)
|
||||
.expect("Failed to parse json")
|
||||
.token
|
||||
}
|
||||
36
server/tests/common/env.rs
Normal file
36
server/tests/common/env.rs
Normal file
@@ -0,0 +1,36 @@
|
||||
#![allow(dead_code)]
|
||||
use std::env::var;
|
||||
|
||||
pub const DB_KEY: &str = "LLDAP_DATABASE_URL";
|
||||
|
||||
pub fn database_url() -> String {
|
||||
let url = var(DB_KEY).ok();
|
||||
url.unwrap_or("sqlite://e2e_test.db?mode=rwc".to_string())
|
||||
}
|
||||
|
||||
pub fn ldap_url() -> String {
|
||||
let port = var("LLDAP_LDAP_PORT").ok();
|
||||
let port = port.unwrap_or("3890".to_string());
|
||||
format!("ldap://localhost:{}", port)
|
||||
}
|
||||
|
||||
pub fn http_url() -> String {
|
||||
let port = var("LLDAP_HTTP_PORT").ok();
|
||||
let port = port.unwrap_or("17170".to_string());
|
||||
format!("http://localhost:{}", port)
|
||||
}
|
||||
|
||||
pub fn admin_dn() -> String {
|
||||
let user = var("LLDAP_LDAP_USER_DN").ok();
|
||||
user.unwrap_or("admin".to_string())
|
||||
}
|
||||
|
||||
pub fn admin_password() -> String {
|
||||
let pass = var("LLDAP_LDAP_USER_PASS").ok();
|
||||
pass.unwrap_or("password".to_string())
|
||||
}
|
||||
|
||||
pub fn base_dn() -> String {
|
||||
let dn = var("LLDAP_LDAP_BASE_DN").ok();
|
||||
dn.unwrap_or("dc=example,dc=com".to_string())
|
||||
}
|
||||
240
server/tests/common/fixture.rs
Normal file
240
server/tests/common/fixture.rs
Normal file
@@ -0,0 +1,240 @@
|
||||
use crate::common::{
|
||||
auth::get_token,
|
||||
env,
|
||||
graphql::{
|
||||
add_user_to_group, create_group, create_user, delete_group_query, delete_user_query, post,
|
||||
AddUserToGroup, CreateGroup, CreateUser, DeleteGroupQuery, DeleteUserQuery,
|
||||
},
|
||||
};
|
||||
use assert_cmd::prelude::*;
|
||||
use nix::{
|
||||
sys::signal::{self, Signal},
|
||||
unistd::Pid,
|
||||
};
|
||||
use reqwest::blocking::{Client, ClientBuilder};
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::process::{Child as ChildProcess, Command};
|
||||
use std::{fs::canonicalize, thread, time::Duration};
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct User {
|
||||
pub username: String,
|
||||
pub groups: Vec<String>,
|
||||
}
|
||||
|
||||
impl User {
|
||||
pub fn new(username: &str, groups: Vec<&str>) -> Self {
|
||||
let username = username.to_owned();
|
||||
let groups = groups.iter().map(|username| username.to_string()).collect();
|
||||
Self { username, groups }
|
||||
}
|
||||
}
|
||||
|
||||
pub struct LLDAPFixture {
|
||||
token: String,
|
||||
client: Client,
|
||||
child: ChildProcess,
|
||||
users: HashSet<String>,
|
||||
groups: HashMap<String, i64>,
|
||||
}
|
||||
|
||||
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 mut started = false;
|
||||
for _ in 0..MAX_HEALTHCHECK_ATTEMPS {
|
||||
let status = create_lldap_command()
|
||||
.arg("healthcheck")
|
||||
.status()
|
||||
.expect("healthcheck fail");
|
||||
if status.success() {
|
||||
started = true;
|
||||
break;
|
||||
}
|
||||
thread::sleep(Duration::from_millis(1000));
|
||||
}
|
||||
assert!(started);
|
||||
let client = ClientBuilder::new()
|
||||
.connect_timeout(std::time::Duration::from_secs(2))
|
||||
.timeout(std::time::Duration::from_secs(5))
|
||||
.redirect(reqwest::redirect::Policy::none())
|
||||
.build()
|
||||
.expect("failed to make http client");
|
||||
let token = get_token(&client);
|
||||
Self {
|
||||
client,
|
||||
token,
|
||||
child,
|
||||
users: HashSet::new(),
|
||||
groups: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn load_state(&mut self, state: &Vec<User>) {
|
||||
let mut users: HashSet<String> = HashSet::new();
|
||||
let mut groups: HashSet<String> = HashSet::new();
|
||||
for user in state {
|
||||
users.insert(user.username.clone());
|
||||
groups.extend(user.groups.clone());
|
||||
}
|
||||
for user in &users {
|
||||
self.add_user(user);
|
||||
}
|
||||
for group in &groups {
|
||||
self.add_group(group);
|
||||
}
|
||||
for User { username, groups } in state {
|
||||
for group in groups {
|
||||
self.add_user_to_group(username, group);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn add_user(&mut self, user: &String) {
|
||||
post::<CreateUser>(
|
||||
&self.client,
|
||||
&self.token,
|
||||
create_user::Variables {
|
||||
user: create_user::CreateUserInput {
|
||||
id: user.clone(),
|
||||
email: format!("{}@lldap.test", user),
|
||||
avatar: None,
|
||||
display_name: None,
|
||||
first_name: None,
|
||||
last_name: None,
|
||||
},
|
||||
},
|
||||
)
|
||||
.expect("failed to add user");
|
||||
self.users.insert(user.clone());
|
||||
}
|
||||
|
||||
fn add_group(&mut self, group: &str) {
|
||||
let id = post::<CreateGroup>(
|
||||
&self.client,
|
||||
&self.token,
|
||||
create_group::Variables {
|
||||
name: group.to_owned(),
|
||||
},
|
||||
)
|
||||
.expect("failed to add group")
|
||||
.create_group
|
||||
.id;
|
||||
self.groups.insert(group.to_owned(), id);
|
||||
}
|
||||
|
||||
fn delete_user(&mut self, user: &String) {
|
||||
post::<DeleteUserQuery>(
|
||||
&self.client,
|
||||
&self.token,
|
||||
delete_user_query::Variables { user: user.clone() },
|
||||
)
|
||||
.expect("failed to delete user");
|
||||
self.users.remove(user);
|
||||
}
|
||||
|
||||
fn delete_group(&mut self, group: &String) {
|
||||
let group_id = self.groups.get(group).unwrap();
|
||||
post::<DeleteGroupQuery>(
|
||||
&self.client,
|
||||
&self.token,
|
||||
delete_group_query::Variables {
|
||||
group_id: *group_id,
|
||||
},
|
||||
)
|
||||
.expect("failed to delete group");
|
||||
self.groups.remove(group);
|
||||
}
|
||||
|
||||
fn add_user_to_group(&mut self, user: &str, group: &String) {
|
||||
let group_id = self.groups.get(group).unwrap();
|
||||
post::<AddUserToGroup>(
|
||||
&self.client,
|
||||
&self.token,
|
||||
add_user_to_group::Variables {
|
||||
user: user.to_owned(),
|
||||
group: *group_id,
|
||||
},
|
||||
)
|
||||
.expect("failed to add user to group");
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for LLDAPFixture {
|
||||
fn drop(&mut self) {
|
||||
let users = self.users.clone();
|
||||
for user in users {
|
||||
self.delete_user(&user);
|
||||
}
|
||||
let groups = self.groups.clone();
|
||||
for group in groups.keys() {
|
||||
self.delete_group(group);
|
||||
}
|
||||
let result = signal::kill(
|
||||
Pid::from_raw(self.child.id().try_into().unwrap()),
|
||||
Signal::SIGTERM,
|
||||
);
|
||||
if let Err(err) = result {
|
||||
println!("Failed to send kill signal: {:?}", err);
|
||||
let _ = self
|
||||
.child
|
||||
.kill()
|
||||
.map_err(|err| println!("Failed to kill LLDAP: {:?}", err));
|
||||
return;
|
||||
}
|
||||
|
||||
for _ in 0..10 {
|
||||
let status = self.child.try_wait();
|
||||
if status.is_err() {}
|
||||
match status {
|
||||
Err(e) => {
|
||||
println!(
|
||||
"Failed to get status while waiting for graceful exit: {}",
|
||||
e
|
||||
);
|
||||
break;
|
||||
}
|
||||
Ok(None) => {
|
||||
println!("LLDAP still running, sleeping for 1 second.");
|
||||
}
|
||||
Ok(Some(status)) => {
|
||||
if !status.success() {
|
||||
println!("LLDAP exited with status {}", status)
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
thread::sleep(Duration::from_millis(1000));
|
||||
}
|
||||
println!("LLDAP alive after 10 seconds, forcing exit.");
|
||||
let _ = self
|
||||
.child
|
||||
.kill()
|
||||
.map_err(|err| println!("Failed to kill LLDAP: {:?}", err));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_id(prefix: Option<&str>) -> String {
|
||||
let id = Uuid::new_v4();
|
||||
let id = format!("{}-lldap-test", id.simple());
|
||||
match prefix {
|
||||
Some(prefix) => format!("{}{}", prefix, id),
|
||||
None => id,
|
||||
}
|
||||
}
|
||||
|
||||
fn create_lldap_command() -> 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");
|
||||
let db_url = env::database_url();
|
||||
cmd.current_dir(path);
|
||||
cmd.env(env::DB_KEY, db_url);
|
||||
cmd
|
||||
}
|
||||
121
server/tests/common/graphql.rs
Normal file
121
server/tests/common/graphql.rs
Normal file
@@ -0,0 +1,121 @@
|
||||
use crate::common::env;
|
||||
use anyhow::{anyhow, Context, Result};
|
||||
use graphql_client::GraphQLQuery;
|
||||
use reqwest::blocking::Client;
|
||||
|
||||
pub type DateTimeUtc = chrono::DateTime<chrono::Utc>;
|
||||
|
||||
#[derive(GraphQLQuery)]
|
||||
#[graphql(
|
||||
schema_path = "../schema.graphql",
|
||||
query_path = "tests/queries/add_user_to_group.graphql",
|
||||
response_derives = "Debug",
|
||||
variables_derives = "Debug,Clone",
|
||||
custom_scalars_module = "crate::common::graphql"
|
||||
)]
|
||||
pub struct AddUserToGroup;
|
||||
|
||||
#[derive(GraphQLQuery)]
|
||||
#[graphql(
|
||||
schema_path = "../schema.graphql",
|
||||
query_path = "tests/queries/create_user.graphql",
|
||||
response_derives = "Debug",
|
||||
variables_derives = "Debug,Clone",
|
||||
custom_scalars_module = "crate::common::graphql"
|
||||
)]
|
||||
pub struct CreateUser;
|
||||
|
||||
#[derive(GraphQLQuery)]
|
||||
#[graphql(
|
||||
schema_path = "../schema.graphql",
|
||||
query_path = "tests/queries/create_group.graphql",
|
||||
response_derives = "Debug",
|
||||
variables_derives = "Debug,Clone",
|
||||
custom_scalars_module = "crate::common::graphql"
|
||||
)]
|
||||
pub struct CreateGroup;
|
||||
|
||||
#[derive(GraphQLQuery)]
|
||||
#[graphql(
|
||||
schema_path = "../schema.graphql",
|
||||
query_path = "tests/queries/list_users.graphql",
|
||||
response_derives = "Debug",
|
||||
custom_scalars_module = "crate::common::graphql"
|
||||
)]
|
||||
pub struct ListUsers;
|
||||
|
||||
#[derive(GraphQLQuery)]
|
||||
#[graphql(
|
||||
schema_path = "../schema.graphql",
|
||||
query_path = "tests/queries/get_user_details.graphql",
|
||||
response_derives = "Debug",
|
||||
variables_derives = "Debug,Clone",
|
||||
custom_scalars_module = "crate::common::graphql"
|
||||
)]
|
||||
pub struct GetUserDetails;
|
||||
|
||||
#[derive(GraphQLQuery)]
|
||||
#[graphql(
|
||||
schema_path = "../schema.graphql",
|
||||
query_path = "tests/queries/list_groups.graphql",
|
||||
response_derives = "Debug",
|
||||
custom_scalars_module = "crate::common::graphql"
|
||||
)]
|
||||
pub struct ListGroups;
|
||||
|
||||
#[derive(GraphQLQuery)]
|
||||
#[graphql(
|
||||
schema_path = "../schema.graphql",
|
||||
query_path = "tests/queries/delete_group.graphql",
|
||||
response_derives = "Debug",
|
||||
custom_scalars_module = "crate::common::graphql"
|
||||
)]
|
||||
pub struct DeleteGroupQuery;
|
||||
|
||||
#[derive(GraphQLQuery)]
|
||||
#[graphql(
|
||||
schema_path = "../schema.graphql",
|
||||
query_path = "tests/queries/delete_user.graphql",
|
||||
response_derives = "Debug",
|
||||
custom_scalars_module = "crate::common::graphql"
|
||||
)]
|
||||
pub struct DeleteUserQuery;
|
||||
|
||||
pub fn post<QueryType>(
|
||||
client: &Client,
|
||||
token: &String,
|
||||
variables: QueryType::Variables,
|
||||
) -> Result<QueryType::ResponseData>
|
||||
where
|
||||
QueryType: GraphQLQuery + 'static,
|
||||
{
|
||||
let unwrap_graphql_response = |graphql_client::Response { data, errors, .. }| {
|
||||
data.ok_or_else(|| {
|
||||
anyhow!(
|
||||
"Errors: [{}]",
|
||||
errors
|
||||
.unwrap_or_default()
|
||||
.iter()
|
||||
.map(ToString::to_string)
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ")
|
||||
)
|
||||
})
|
||||
};
|
||||
let url = env::http_url() + "/api/graphql";
|
||||
let auth_header = format!("Bearer {}", token);
|
||||
client
|
||||
.post(url)
|
||||
.header(reqwest::header::AUTHORIZATION, auth_header)
|
||||
// Request body.
|
||||
.json(&QueryType::build_query(variables))
|
||||
.send()
|
||||
.context("while sending a request to the LLDAP server")?
|
||||
.error_for_status()
|
||||
.context("error from an LLDAP response")?
|
||||
// Parse response as Json.
|
||||
.json::<graphql_client::Response<QueryType::ResponseData>>()
|
||||
.context("while parsing backend response")
|
||||
.and_then(unwrap_graphql_response)
|
||||
.context("GraphQL error from an LLDAP response")
|
||||
}
|
||||
4
server/tests/common/mod.rs
Normal file
4
server/tests/common/mod.rs
Normal file
@@ -0,0 +1,4 @@
|
||||
pub mod auth;
|
||||
pub mod env;
|
||||
pub mod fixture;
|
||||
pub mod graphql;
|
||||
70
server/tests/graphql.rs
Normal file
70
server/tests/graphql.rs
Normal file
@@ -0,0 +1,70 @@
|
||||
use crate::common::{
|
||||
auth::get_token,
|
||||
env,
|
||||
fixture::{new_id, LLDAPFixture, User},
|
||||
graphql::{get_user_details, list_users, post, GetUserDetails, ListUsers},
|
||||
};
|
||||
use reqwest::blocking::ClientBuilder;
|
||||
use serial_test::file_serial;
|
||||
use std::collections::HashSet;
|
||||
mod common;
|
||||
|
||||
#[test]
|
||||
#[file_serial]
|
||||
fn list_users() {
|
||||
let mut fixture = LLDAPFixture::new();
|
||||
let prefix = "graphql-list_users-";
|
||||
let user1_name = new_id(Some(prefix));
|
||||
let user2_name = new_id(Some(prefix));
|
||||
let user3_name = new_id(Some(prefix));
|
||||
let group1_name = new_id(Some(prefix));
|
||||
let group2_name = new_id(Some(prefix));
|
||||
let initial_state = vec![
|
||||
User::new(&user1_name, vec![&group1_name]),
|
||||
User::new(&user2_name, vec![&group1_name, &group2_name]),
|
||||
User::new(&user3_name, vec![]),
|
||||
];
|
||||
fixture.load_state(&initial_state);
|
||||
|
||||
let client = ClientBuilder::new()
|
||||
.connect_timeout(std::time::Duration::from_secs(2))
|
||||
.timeout(std::time::Duration::from_secs(5))
|
||||
.redirect(reqwest::redirect::Policy::none())
|
||||
.build()
|
||||
.expect("failed to make http client");
|
||||
let token = get_token(&client);
|
||||
let result =
|
||||
post::<ListUsers>(&client, &token, list_users::Variables {}).expect("failed to list users");
|
||||
let users: HashSet<String> = result.users.iter().map(|user| user.id.clone()).collect();
|
||||
assert!(users.contains(&user1_name));
|
||||
assert!(users.contains(&user2_name));
|
||||
assert!(users.contains(&user3_name));
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[file_serial]
|
||||
fn get_admin() {
|
||||
let mut _fixture = LLDAPFixture::new();
|
||||
let client = ClientBuilder::new()
|
||||
.connect_timeout(std::time::Duration::from_secs(2))
|
||||
.timeout(std::time::Duration::from_secs(5))
|
||||
.redirect(reqwest::redirect::Policy::none())
|
||||
.build()
|
||||
.expect("failed to make http client");
|
||||
let admin_name = env::admin_dn();
|
||||
let admin_group_name = "lldap_admin";
|
||||
let token = get_token(&client);
|
||||
let result = post::<GetUserDetails>(
|
||||
&client,
|
||||
&token,
|
||||
get_user_details::Variables { id: admin_name },
|
||||
)
|
||||
.expect("failed to get admin");
|
||||
let admin_groups: HashSet<String> = result
|
||||
.user
|
||||
.groups
|
||||
.iter()
|
||||
.map(|group| group.display_name.clone())
|
||||
.collect();
|
||||
assert!(admin_groups.contains(admin_group_name));
|
||||
}
|
||||
57
server/tests/integrations.rs
Normal file
57
server/tests/integrations.rs
Normal file
@@ -0,0 +1,57 @@
|
||||
use std::collections::HashSet;
|
||||
|
||||
use crate::common::{
|
||||
env,
|
||||
fixture::{new_id, LLDAPFixture, User},
|
||||
};
|
||||
use ldap3::{LdapConn, Scope, SearchEntry};
|
||||
use serial_test::file_serial;
|
||||
mod common;
|
||||
|
||||
#[test]
|
||||
#[file_serial]
|
||||
fn gitea() {
|
||||
let mut fixture = LLDAPFixture::new();
|
||||
let gitea_user_group = new_id(Some("gitea_user-"));
|
||||
let gitea_admin_group = new_id(Some("gitea_admin-"));
|
||||
let gitea_user1 = new_id(Some("gitea1-"));
|
||||
let gitea_user2 = new_id(Some("gitea2-"));
|
||||
let gitea_user3 = new_id(Some("gitea3-"));
|
||||
let initial_state = vec![
|
||||
User::new(&gitea_user1, vec![&gitea_user_group, &gitea_admin_group]),
|
||||
User::new(&gitea_user2, vec![&gitea_user_group]),
|
||||
User::new(&gitea_user3, vec![]),
|
||||
];
|
||||
fixture.load_state(&initial_state);
|
||||
|
||||
let mut ldap =
|
||||
LdapConn::new(env::ldap_url().as_str()).expect("failed to create ldap connection");
|
||||
let base_dn = env::base_dn();
|
||||
let bind_dn = format!("uid={},ou=people,{}", env::admin_dn(), base_dn);
|
||||
ldap.simple_bind(bind_dn.as_str(), env::admin_password().as_str())
|
||||
.expect("failed to bind to ldap");
|
||||
|
||||
let user_base = format!("ou=people,{}", base_dn);
|
||||
let attrs = vec!["uid", "givenName", "sn", "mail", "jpegPhoto"];
|
||||
let results = ldap
|
||||
.search(
|
||||
user_base.as_str(),
|
||||
Scope::Subtree,
|
||||
format!("(memberof=cn={},ou=groups,{})", gitea_user_group, base_dn).as_str(),
|
||||
attrs,
|
||||
)
|
||||
.expect("failed to find gitea users")
|
||||
.success()
|
||||
.expect("failed to get gitea user results")
|
||||
.0;
|
||||
let mut found_users: HashSet<String> = HashSet::new();
|
||||
for result in results {
|
||||
let attrs = SearchEntry::construct(result).attrs;
|
||||
let user = attrs.get("uid").unwrap().get(0).unwrap();
|
||||
found_users.insert(user.clone());
|
||||
}
|
||||
assert!(found_users.contains(&gitea_user1));
|
||||
assert!(found_users.contains(&gitea_user2));
|
||||
assert!(!found_users.contains(&gitea_user3));
|
||||
ldap.unbind().expect("failed to unbind ldap connection");
|
||||
}
|
||||
112
server/tests/ldap.rs
Normal file
112
server/tests/ldap.rs
Normal file
@@ -0,0 +1,112 @@
|
||||
use std::collections::{HashMap, HashSet};
|
||||
|
||||
use crate::common::{
|
||||
env,
|
||||
fixture::{new_id, LLDAPFixture, User},
|
||||
};
|
||||
use ldap3::{LdapConn, Scope, SearchEntry, SearchResult};
|
||||
use serial_test::file_serial;
|
||||
mod common;
|
||||
|
||||
#[test]
|
||||
#[file_serial]
|
||||
fn basic_users_search() {
|
||||
let mut fixture = LLDAPFixture::new();
|
||||
let prefix = "ldap-basic_users_search-";
|
||||
let user1_name = new_id(Some(prefix));
|
||||
let user2_name = new_id(Some(prefix));
|
||||
let user3_name = new_id(Some(prefix));
|
||||
let group1_name = new_id(Some(prefix));
|
||||
let group2_name = new_id(Some(prefix));
|
||||
let initial_state = vec![
|
||||
User::new(&user1_name, vec![&group1_name]),
|
||||
User::new(&user2_name, vec![&group1_name, &group2_name]),
|
||||
User::new(&user3_name, vec![]),
|
||||
];
|
||||
fixture.load_state(&initial_state);
|
||||
|
||||
let mut ldap =
|
||||
LdapConn::new(env::ldap_url().as_str()).expect("failed to create ldap connection");
|
||||
let base_dn = env::base_dn();
|
||||
let bind_dn = format!("uid={},ou=people,{}", env::admin_dn(), base_dn);
|
||||
ldap.simple_bind(bind_dn.as_str(), env::admin_password().as_str())
|
||||
.expect("failed to bind to ldap");
|
||||
|
||||
let attrs = vec!["uid", "memberof"];
|
||||
let found_users = get_users_and_groups(
|
||||
ldap.search(
|
||||
env::base_dn().as_str(),
|
||||
Scope::Subtree,
|
||||
"(objectclass=person)",
|
||||
attrs,
|
||||
)
|
||||
.expect("failed to find users"),
|
||||
);
|
||||
assert!(found_users.contains_key(&user1_name));
|
||||
assert!(found_users
|
||||
.get(&user1_name)
|
||||
.unwrap()
|
||||
.contains(format!("cn={},ou=groups,{}", &group1_name, base_dn).as_str()));
|
||||
assert!(found_users.contains_key(&user2_name));
|
||||
assert!(found_users
|
||||
.get(&user2_name)
|
||||
.unwrap()
|
||||
.contains(format!("cn={},ou=groups,{}", &group1_name, base_dn).as_str()));
|
||||
assert!(found_users
|
||||
.get(&user2_name)
|
||||
.unwrap()
|
||||
.contains(format!("cn={},ou=groups,{}", &group2_name, base_dn).as_str()));
|
||||
assert!(found_users.contains_key(&user3_name));
|
||||
assert!(found_users.get(&user3_name).unwrap().is_empty());
|
||||
ldap.unbind().expect("failed to unbind ldap connection");
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[file_serial]
|
||||
fn admin_search() {
|
||||
let mut _fixture = LLDAPFixture::new();
|
||||
|
||||
let mut ldap =
|
||||
LdapConn::new(env::ldap_url().as_str()).expect("failed to create ldap connection");
|
||||
let base_dn = env::base_dn();
|
||||
let bind_dn = format!("uid={},ou=people,{}", env::admin_dn(), base_dn);
|
||||
ldap.simple_bind(bind_dn.as_str(), env::admin_password().as_str())
|
||||
.expect("failed to bind to ldap");
|
||||
|
||||
let attrs = vec!["uid", "memberof"];
|
||||
let admin_name = env::admin_dn();
|
||||
let admin_group_name = "lldap_admin";
|
||||
let found_users = get_users_and_groups(
|
||||
ldap.search(
|
||||
env::base_dn().as_str(),
|
||||
Scope::Subtree,
|
||||
format!("(&(objectclass=person)(uid={}))", admin_name).as_str(),
|
||||
attrs,
|
||||
)
|
||||
.expect("failed to find admin"),
|
||||
);
|
||||
|
||||
assert!(found_users.contains_key(&admin_name));
|
||||
assert!(found_users
|
||||
.get(&admin_name)
|
||||
.unwrap()
|
||||
.contains(format!("cn={},ou=groups,{}", admin_group_name, base_dn).as_str()));
|
||||
ldap.unbind().expect("failed to unbind ldap connection");
|
||||
}
|
||||
|
||||
fn get_users_and_groups(results: SearchResult) -> HashMap<String, HashSet<String>> {
|
||||
let results = results
|
||||
.success()
|
||||
.expect("failed to get successful result")
|
||||
.0;
|
||||
let mut found_users: HashMap<String, HashSet<String>> = HashMap::new();
|
||||
for result in results {
|
||||
let attrs = SearchEntry::construct(result).attrs;
|
||||
let user = attrs.get("uid").unwrap().get(0).unwrap();
|
||||
let user_groups = attrs.get("memberof").unwrap().clone();
|
||||
let mut groups: HashSet<String> = HashSet::new();
|
||||
groups.extend(user_groups.clone());
|
||||
found_users.insert(user.clone(), groups);
|
||||
}
|
||||
found_users
|
||||
}
|
||||
5
server/tests/queries/add_user_to_group.graphql
Normal file
5
server/tests/queries/add_user_to_group.graphql
Normal file
@@ -0,0 +1,5 @@
|
||||
mutation AddUserToGroup($user: String!, $group: Int!) {
|
||||
addUserToGroup(userId: $user, groupId: $group) {
|
||||
ok
|
||||
}
|
||||
}
|
||||
6
server/tests/queries/create_group.graphql
Normal file
6
server/tests/queries/create_group.graphql
Normal file
@@ -0,0 +1,6 @@
|
||||
mutation CreateGroup($name: String!) {
|
||||
createGroup(name: $name) {
|
||||
id
|
||||
displayName
|
||||
}
|
||||
}
|
||||
5
server/tests/queries/create_user.graphql
Normal file
5
server/tests/queries/create_user.graphql
Normal file
@@ -0,0 +1,5 @@
|
||||
mutation CreateUser($user: CreateUserInput!) {
|
||||
createUser(user: $user) {
|
||||
id
|
||||
}
|
||||
}
|
||||
5
server/tests/queries/delete_group.graphql
Normal file
5
server/tests/queries/delete_group.graphql
Normal file
@@ -0,0 +1,5 @@
|
||||
mutation DeleteGroupQuery($groupId: Int!) {
|
||||
deleteGroup(groupId: $groupId) {
|
||||
ok
|
||||
}
|
||||
}
|
||||
5
server/tests/queries/delete_user.graphql
Normal file
5
server/tests/queries/delete_user.graphql
Normal file
@@ -0,0 +1,5 @@
|
||||
mutation DeleteUserQuery($user: String!) {
|
||||
deleteUser(userId: $user) {
|
||||
ok
|
||||
}
|
||||
}
|
||||
16
server/tests/queries/get_user_details.graphql
Normal file
16
server/tests/queries/get_user_details.graphql
Normal file
@@ -0,0 +1,16 @@
|
||||
query GetUserDetails($id: String!) {
|
||||
user(userId: $id) {
|
||||
id
|
||||
email
|
||||
displayName
|
||||
firstName
|
||||
lastName
|
||||
avatar
|
||||
creationDate
|
||||
uuid
|
||||
groups {
|
||||
id
|
||||
displayName
|
||||
}
|
||||
}
|
||||
}
|
||||
9
server/tests/queries/list_groups.graphql
Normal file
9
server/tests/queries/list_groups.graphql
Normal file
@@ -0,0 +1,9 @@
|
||||
query ListGroups {
|
||||
groups {
|
||||
id
|
||||
displayName
|
||||
users {
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
5
server/tests/queries/list_users.graphql
Normal file
5
server/tests/queries/list_users.graphql
Normal file
@@ -0,0 +1,5 @@
|
||||
query ListUsers {
|
||||
users(filters: null) {
|
||||
id
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,17 @@
|
||||
[package]
|
||||
name = "lldap_set_password"
|
||||
version = "0.1.0"
|
||||
authors = ["Valentin Tolmer <valentin@tolmer.fr>"]
|
||||
description = "CLI tool to set a user password in LLDAP"
|
||||
edition = "2021"
|
||||
homepage = "https://github.com/lldap/lldap"
|
||||
license = "GPL-3.0-only"
|
||||
name = "lldap_set_password"
|
||||
repository = "https://github.com/lldap/lldap"
|
||||
version = "0.1.0"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
anyhow = "*"
|
||||
anyhow = "1"
|
||||
rand = "0.8"
|
||||
serde = "1"
|
||||
serde_json = "1"
|
||||
@@ -16,10 +21,10 @@ features = ["std", "color", "suggestions", "derive", "env"]
|
||||
version = "4"
|
||||
|
||||
[dependencies.lldap_auth]
|
||||
path = "../auth"
|
||||
version = "0.3"
|
||||
features = ["opaque_client"]
|
||||
|
||||
[dependencies.reqwest]
|
||||
version = "*"
|
||||
version = "0.11"
|
||||
default-features = false
|
||||
features = ["json", "blocking", "rustls-tls"]
|
||||
|
||||
Reference in New Issue
Block a user