Compare commits

...

202 commits

Author SHA1 Message Date
dependabot[bot]
d0cfc69a09
Bump crossbeam-channel from 0.5.14 to 0.5.15 in the cargo group (#3560)
Bumps the cargo group with 1 update: [crossbeam-channel](https://github.com/crossbeam-rs/crossbeam).


Updates `crossbeam-channel` from 0.5.14 to 0.5.15
- [Release notes](https://github.com/crossbeam-rs/crossbeam/releases)
- [Changelog](https://github.com/crossbeam-rs/crossbeam/blob/master/CHANGELOG.md)
- [Commits](https://github.com/crossbeam-rs/crossbeam/compare/crossbeam-channel-0.5.14...crossbeam-channel-0.5.15)

---
updated-dependencies:
- dependency-name: crossbeam-channel
  dependency-version: 0.5.15
  dependency-type: indirect
  dependency-group: cargo
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-11 10:12:31 +10:00
Firstyear
b113262357
Improve token handling (#3553)
It was possible that a token could be updated in a way that caused
existing cached information to be lost if an event was delayed
in it's write to the user token.

To prevent this, the writes to user tokens now require the HsmLock
to be held, and refresh the token just ahead of writing to ensure
that these data can't be lost. The benefit to this approach is that
readers remain unblocked by a writer.
2025-04-09 14:49:06 +10:00
dependabot[bot]
d025e8fff0
Bump tokio from 1.44.1 to 1.44.2 in the cargo group (#3549)
Bumps the cargo group with 1 update: [tokio](https://github.com/tokio-rs/tokio).


Updates `tokio` from 1.44.1 to 1.44.2
- [Release notes](https://github.com/tokio-rs/tokio/releases)
- [Commits](https://github.com/tokio-rs/tokio/compare/tokio-1.44.1...tokio-1.44.2)

---
updated-dependencies:
- dependency-name: tokio
  dependency-version: 1.44.2
  dependency-type: direct:production
  dependency-group: cargo
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-09 09:39:19 +10:00
Firstyear
aee9ed05f3
Update fs4 and improve klock handling (#3551) 2025-04-08 05:04:26 +00:00
James Hodgkinson
5458b13398
Less footguns (#3552) 2025-04-08 04:48:53 +00:00
Firstyear
94b6287e27
Unify unix config parser (#3533)
* Unify unix config parser
* Document the various structs
* Compiler Update
2025-04-08 14:21:26 +10:00
dependabot[bot]
b6813a11d3
Bump openssl from 0.10.71 to 0.10.72 in the cargo group (#3544)
Bumps the cargo group with 1 update: [openssl](https://github.com/sfackler/rust-openssl).


Updates `openssl` from 0.10.71 to 0.10.72
- [Release notes](https://github.com/sfackler/rust-openssl/releases)
- [Commits](https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.71...openssl-v0.10.72)

---
updated-dependencies:
- dependency-name: openssl
  dependency-version: 0.10.72
  dependency-type: direct:production
  dependency-group: cargo
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-08 01:31:20 +00:00
dependabot[bot]
d79188559f
Bump the all group in /pykanidm with 8 updates (#3547)
Bumps the all group in /pykanidm with 8 updates:

| Package | From | To |
| --- | --- | --- |
| [pydantic](https://github.com/pydantic/pydantic) | `2.11.1` | `2.11.2` |
| [aiohttp](https://github.com/aio-libs/aiohttp) | `3.11.14` | `3.11.16` |
| [authlib](https://github.com/lepture/authlib) | `1.5.1` | `1.5.2` |
| [ruff](https://github.com/astral-sh/ruff) | `0.11.2` | `0.11.4` |
| [coverage](https://github.com/nedbat/coveragepy) | `7.7.1` | `7.8.0` |
| [mkdocs-material](https://github.com/squidfunk/mkdocs-material) | `9.6.10` | `9.6.11` |
| [mkdocstrings](https://github.com/mkdocstrings/mkdocstrings) | `0.29.0` | `0.29.1` |
| [mkdocstrings-python](https://github.com/mkdocstrings/python) | `1.16.8` | `1.16.10` |


Updates `pydantic` from 2.11.1 to 2.11.2
- [Release notes](https://github.com/pydantic/pydantic/releases)
- [Changelog](https://github.com/pydantic/pydantic/blob/main/HISTORY.md)
- [Commits](https://github.com/pydantic/pydantic/compare/v2.11.1...v2.11.2)

Updates `aiohttp` from 3.11.14 to 3.11.16
- [Release notes](https://github.com/aio-libs/aiohttp/releases)
- [Changelog](https://github.com/aio-libs/aiohttp/blob/master/CHANGES.rst)
- [Commits](https://github.com/aio-libs/aiohttp/compare/v3.11.14...v3.11.16)

Updates `authlib` from 1.5.1 to 1.5.2
- [Release notes](https://github.com/lepture/authlib/releases)
- [Changelog](https://github.com/lepture/authlib/blob/main/docs/changelog.rst)
- [Commits](https://github.com/lepture/authlib/compare/v1.5.1...v1.5.2)

Updates `ruff` from 0.11.2 to 0.11.4
- [Release notes](https://github.com/astral-sh/ruff/releases)
- [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md)
- [Commits](https://github.com/astral-sh/ruff/compare/0.11.2...0.11.4)

Updates `coverage` from 7.7.1 to 7.8.0
- [Release notes](https://github.com/nedbat/coveragepy/releases)
- [Changelog](https://github.com/nedbat/coveragepy/blob/master/CHANGES.rst)
- [Commits](https://github.com/nedbat/coveragepy/compare/7.7.1...7.8.0)

Updates `mkdocs-material` from 9.6.10 to 9.6.11
- [Release notes](https://github.com/squidfunk/mkdocs-material/releases)
- [Changelog](https://github.com/squidfunk/mkdocs-material/blob/master/CHANGELOG)
- [Commits](https://github.com/squidfunk/mkdocs-material/compare/9.6.10...9.6.11)

Updates `mkdocstrings` from 0.29.0 to 0.29.1
- [Release notes](https://github.com/mkdocstrings/mkdocstrings/releases)
- [Changelog](https://github.com/mkdocstrings/mkdocstrings/blob/main/CHANGELOG.md)
- [Commits](https://github.com/mkdocstrings/mkdocstrings/compare/0.29.0...0.29.1)

Updates `mkdocstrings-python` from 1.16.8 to 1.16.10
- [Release notes](https://github.com/mkdocstrings/python/releases)
- [Changelog](https://github.com/mkdocstrings/python/blob/main/CHANGELOG.md)
- [Commits](https://github.com/mkdocstrings/python/compare/1.16.8...1.16.10)

---
updated-dependencies:
- dependency-name: pydantic
  dependency-version: 2.11.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: aiohttp
  dependency-version: 3.11.16
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: authlib
  dependency-version: 1.5.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: ruff
  dependency-version: 0.11.4
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: coverage
  dependency-version: 7.8.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: all
- dependency-name: mkdocs-material
  dependency-version: 9.6.11
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: mkdocstrings
  dependency-version: 0.29.1
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: mkdocstrings-python
  dependency-version: 1.16.10
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: all
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-07 14:21:35 +10:00
Arian van Putten
ad012cd6fd
implement notify-reload protocol (#3540) 2025-04-04 09:24:14 +10:00
Firstyear
82a883089f
Allow versioning of server configs (#3515)
This allows our server configuration to be versioned, in preparation
for a change related to the proxy protocol additions.
2025-04-02 02:44:19 +00:00
Firstyear
a2eae53328
20250314 remove protected plugin (#3504)
Removes the protected plugin into an access control module so that it's outputs can be properly represented in effective access checks.
2025-04-01 01:00:56 +00:00
dependabot[bot]
ec3db91da0
Bump the all group with 10 updates (#3539)
* Bump the all group with 10 updates

Bumps the all group with 10 updates:

| Package | From | To |
| --- | --- | --- |
| [clap](https://github.com/clap-rs/clap) | `4.5.32` | `4.5.34` |
| [itertools](https://github.com/rust-itertools/itertools) | `0.13.0` | `0.14.0` |
| [lru](https://github.com/jeromefroe/lru-rs) | `0.12.5` | `0.13.0` |
| [rand](https://github.com/rust-random/rand) | `0.8.5` | `0.9.0` |
| [rand_chacha](https://github.com/rust-random/rand) | `0.3.1` | `0.9.0` |
| [whoami](https://github.com/ardaku/whoami) | `1.5.2` | `1.6.0` |
| [axum-extra](https://github.com/tokio-rs/axum) | `0.9.6` | `0.10.1` |
| [axum-macros](https://github.com/tokio-rs/axum) | `0.4.2` | `0.5.0` |
| [fantoccini](https://github.com/jonhoo/fantoccini) | `0.21.4` | `0.21.5` |
| [jsonschema](https://github.com/Stranger6667/jsonschema) | `0.29.0` | `0.29.1` |


Updates `clap` from 4.5.32 to 4.5.34
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/clap_complete-v4.5.32...clap_complete-v4.5.34)

Updates `itertools` from 0.13.0 to 0.14.0
- [Changelog](https://github.com/rust-itertools/itertools/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rust-itertools/itertools/compare/v0.13.0...v0.14.0)

Updates `lru` from 0.12.5 to 0.13.0
- [Changelog](https://github.com/jeromefroe/lru-rs/blob/master/CHANGELOG.md)
- [Commits](https://github.com/jeromefroe/lru-rs/compare/0.12.5...0.13.0)

Updates `rand` from 0.8.5 to 0.9.0
- [Release notes](https://github.com/rust-random/rand/releases)
- [Changelog](https://github.com/rust-random/rand/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rust-random/rand/compare/0.8.5...0.9.0)

Updates `rand_chacha` from 0.3.1 to 0.9.0
- [Release notes](https://github.com/rust-random/rand/releases)
- [Changelog](https://github.com/rust-random/rand/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rust-random/rand/compare/rand_chacha-0.3.1...0.9.0)

Updates `whoami` from 1.5.2 to 1.6.0
- [Release notes](https://github.com/ardaku/whoami/releases)
- [Changelog](https://github.com/ardaku/whoami/blob/v1.6.0/CHANGELOG.md)
- [Commits](https://github.com/ardaku/whoami/compare/v1.5.2...v1.6.0)

Updates `axum-extra` from 0.9.6 to 0.10.1
- [Release notes](https://github.com/tokio-rs/axum/releases)
- [Changelog](https://github.com/tokio-rs/axum/blob/main/CHANGELOG.md)
- [Commits](https://github.com/tokio-rs/axum/compare/axum-extra-v0.9.6...axum-extra-v0.10.1)

Updates `axum-macros` from 0.4.2 to 0.5.0
- [Release notes](https://github.com/tokio-rs/axum/releases)
- [Changelog](https://github.com/tokio-rs/axum/blob/main/CHANGELOG.md)
- [Commits](https://github.com/tokio-rs/axum/compare/axum-macros-v0.4.2...axum-macros-v0.5.0)

Updates `fantoccini` from 0.21.4 to 0.21.5
- [Commits](https://github.com/jonhoo/fantoccini/compare/v0.21.4...v0.21.5)

Updates `jsonschema` from 0.29.0 to 0.29.1
- [Release notes](https://github.com/Stranger6667/jsonschema/releases)
- [Changelog](https://github.com/Stranger6667/jsonschema/blob/master/CHANGELOG.md)
- [Commits](https://github.com/Stranger6667/jsonschema/compare/rust-v0.29.0...rust-v0.29.1)

---
updated-dependencies:
- dependency-name: clap
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: itertools
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: all
- dependency-name: lru
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: all
- dependency-name: rand
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: all
- dependency-name: rand_chacha
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: all
- dependency-name: whoami
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: all
- dependency-name: axum-extra
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: all
- dependency-name: axum-macros
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: all
- dependency-name: fantoccini
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: jsonschema
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all
...

Signed-off-by: dependabot[bot] <support@github.com>

* maint: revert rand and axum packages

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: James Hodgkinson <james@terminaloutcomes.com>
2025-03-31 00:28:22 +00:00
dependabot[bot]
efaef70abe
Bump mozilla-actions/sccache-action from 0.0.8 to 0.0.9 in the all group (#3538)
Bumps the all group with 1 update: [mozilla-actions/sccache-action](https://github.com/mozilla-actions/sccache-action).


Updates `mozilla-actions/sccache-action` from 0.0.8 to 0.0.9
- [Release notes](https://github.com/mozilla-actions/sccache-action/releases)
- [Commits](https://github.com/mozilla-actions/sccache-action/compare/v0.0.8...v0.0.9)

---
updated-dependencies:
- dependency-name: mozilla-actions/sccache-action
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-30 23:25:40 +00:00
dependabot[bot]
5b48f1dfe3
Bump the all group in /pykanidm with 4 updates (#3537)
Bumps the all group in /pykanidm with 4 updates: [pydantic](https://github.com/pydantic/pydantic), [types-requests](https://github.com/python/typeshed), [mkdocs-material](https://github.com/squidfunk/mkdocs-material) and [mkdocstrings-python](https://github.com/mkdocstrings/python).


Updates `pydantic` from 2.10.6 to 2.11.1
- [Release notes](https://github.com/pydantic/pydantic/releases)
- [Changelog](https://github.com/pydantic/pydantic/blob/main/HISTORY.md)
- [Commits](https://github.com/pydantic/pydantic/compare/v2.10.6...v2.11.1)

Updates `types-requests` from 2.32.0.20250306 to 2.32.0.20250328
- [Commits](https://github.com/python/typeshed/commits)

Updates `mkdocs-material` from 9.6.9 to 9.6.10
- [Release notes](https://github.com/squidfunk/mkdocs-material/releases)
- [Changelog](https://github.com/squidfunk/mkdocs-material/blob/master/CHANGELOG)
- [Commits](https://github.com/squidfunk/mkdocs-material/compare/9.6.9...9.6.10)

Updates `mkdocstrings-python` from 1.16.7 to 1.16.8
- [Release notes](https://github.com/mkdocstrings/python/releases)
- [Changelog](https://github.com/mkdocstrings/python/blob/main/CHANGELOG.md)
- [Commits](https://github.com/mkdocstrings/python/compare/1.16.7...1.16.8)

---
updated-dependencies:
- dependency-name: pydantic
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: all
- dependency-name: types-requests
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: mkdocs-material
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: mkdocstrings-python
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: all
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-31 07:54:28 +10:00
Firstyear
567fe7b259
Add max_ber_size to freeipa sync (#3530) 2025-03-28 10:46:00 +10:00
dependabot[bot]
5edc6be51c
Bump the all group in /pykanidm with 5 updates (#3524)
Bumps the all group in /pykanidm with 5 updates:

| Package | From | To |
| --- | --- | --- |
| [aiohttp](https://github.com/aio-libs/aiohttp) | `3.11.13` | `3.11.14` |
| [ruff](https://github.com/astral-sh/ruff) | `0.11.0` | `0.11.2` |
| [coverage](https://github.com/nedbat/coveragepy) | `7.7.0` | `7.7.1` |
| [mkdocs-material](https://github.com/squidfunk/mkdocs-material) | `9.6.8` | `9.6.9` |
| [mkdocstrings-python](https://github.com/mkdocstrings/python) | `1.16.5` | `1.16.7` |


Updates `aiohttp` from 3.11.13 to 3.11.14
- [Release notes](https://github.com/aio-libs/aiohttp/releases)
- [Changelog](https://github.com/aio-libs/aiohttp/blob/master/CHANGES.rst)
- [Commits](https://github.com/aio-libs/aiohttp/compare/v3.11.13...v3.11.14)

Updates `ruff` from 0.11.0 to 0.11.2
- [Release notes](https://github.com/astral-sh/ruff/releases)
- [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md)
- [Commits](https://github.com/astral-sh/ruff/compare/0.11.0...0.11.2)

Updates `coverage` from 7.7.0 to 7.7.1
- [Release notes](https://github.com/nedbat/coveragepy/releases)
- [Changelog](https://github.com/nedbat/coveragepy/blob/master/CHANGES.rst)
- [Commits](https://github.com/nedbat/coveragepy/compare/7.7.0...7.7.1)

Updates `mkdocs-material` from 9.6.8 to 9.6.9
- [Release notes](https://github.com/squidfunk/mkdocs-material/releases)
- [Changelog](https://github.com/squidfunk/mkdocs-material/blob/master/CHANGELOG)
- [Commits](https://github.com/squidfunk/mkdocs-material/compare/9.6.8...9.6.9)

Updates `mkdocstrings-python` from 1.16.5 to 1.16.7
- [Release notes](https://github.com/mkdocstrings/python/releases)
- [Changelog](https://github.com/mkdocstrings/python/blob/main/CHANGELOG.md)
- [Commits](https://github.com/mkdocstrings/python/compare/1.16.5...1.16.7)

---
updated-dependencies:
- dependency-name: aiohttp
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: ruff
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: coverage
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: mkdocs-material
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: mkdocstrings-python
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: all
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-24 11:59:26 +10:00
William Brown
c75c97893e Update Concread 2025-03-22 12:47:18 +10:00
Peter Todd Decker ("Todd")
638904f12c
Update developer_ethics.md (#3520) 2025-03-22 01:58:54 +00:00
Jeff Scrum
e1b9063b99
Update examples.md (#3519)
fix command in OAuth2 Proxy example
2025-03-21 23:18:16 +00:00
Firstyear
bf1e9b0989
Make schema indexing a boolean instead of index types (#3517)
Previously on schema definitions for attributes, the list of index
types was manually set on attributes. The issue with this approach is
that not all index types apply to all attribute syntaxes. This made it
error prone not just to Kanidm developers, but to future users who
want to define custom attributes and may incorrectly index those
attributes.

Instead, this changes the index value to be a boolean to indicate
if this attribute should or should not be indexed. Internally Kanidm
has a list of appropriate indexes to apply to these syntax types.

As part of this change, the tests were reviewed to find missing index
types for syntaxes, and other causes of unindexed searches which led
to some changes around the dyngroup plugin (which pushes the boundaries
of a lot of things in Kani due to how it works).
2025-03-21 02:13:54 +00:00
Foosec
11c7266ff3
Add missing lld dependency and fix syntax typo (#3490)
* Add missing lld dependency and fix syntax typo in devcontainer_postcreate.sh
* replace pushd/popd with shell agnostic solution and do not throw away std out/err
---------
Co-authored-by: foobar <foobar>
2025-03-21 01:51:58 +00:00
Katherina Walshe-Grey
ef638a62e9
Update shell.nix to work with stable nixpkgs (#3514)
The existing shell.nix uses whatever versions of rustc and cargo are in
the system nixpkgs. In the current stable nixpkgs version (24.11), this
is rustc 1.82.0. Unfortunately, we depend on the `strict_provenance`
feature, which was unstable before 1.84.0. (See: kanidm/concread#132)

This patch makes minimal changes to shell.nix to overlay nixpkgs with
the rustc version defined in rust-toolchain.toml, enabling Kanidm to
build locally on stable versions of NixOS.

Co-authored-by: Firstyear <william@blackhats.net.au>
2025-03-20 13:06:51 +10:00
Firstyear
f86bc03a93
Improve unixd tasks channel comments (#3510) 2025-03-19 00:57:39 +00:00
Jinna Kiisuo
46eda59cff
Update kanidm_ppa_automation reference to latest (#3512) 2025-03-18 12:10:36 +00:00
Firstyear
b13951a79b
Add set-description to group tooling (#3511) 2025-03-18 21:54:20 +10:00
Jinna Kiisuo
1e91f244a2
packaging: Add kanidmd deb package, update documentation (#3506)
* packaging: Use cargo-deb multiarch support

This allows building all platforms from one definition,
assuming the --multiarch=foreign flag is used.

* packaging: Use correct path naming for unixd service files

While cargo-deb works around the mistake, better to name them as per the
rules: https://github.com/kornelski/cargo-deb/blob/main/systemd.md#systemd-unit-file-naming

* docs: Update book chapter on Debian packaging

* packaging: Shift Debian builds to a separate build profile

* packaging: Add deb for kanidmd
2025-03-18 12:10:42 +10:00
dependabot[bot]
23bb656c6b
Bump the all group in /pykanidm with 5 updates (#3508)
Bumps the all group in /pykanidm with 5 updates:

| Package | From | To |
| --- | --- | --- |
| [ruff](https://github.com/astral-sh/ruff) | `0.9.10` | `0.11.0` |
| [coverage](https://github.com/nedbat/coveragepy) | `7.6.12` | `7.7.0` |
| [mkdocs-material](https://github.com/squidfunk/mkdocs-material) | `9.6.7` | `9.6.8` |
| [mkdocstrings](https://github.com/mkdocstrings/mkdocstrings) | `0.28.3` | `0.29.0` |
| [mkdocstrings-python](https://github.com/mkdocstrings/python) | `1.16.3` | `1.16.5` |


Updates `ruff` from 0.9.10 to 0.11.0
- [Release notes](https://github.com/astral-sh/ruff/releases)
- [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md)
- [Commits](https://github.com/astral-sh/ruff/compare/0.9.10...0.11.0)

Updates `coverage` from 7.6.12 to 7.7.0
- [Release notes](https://github.com/nedbat/coveragepy/releases)
- [Changelog](https://github.com/nedbat/coveragepy/blob/master/CHANGES.rst)
- [Commits](https://github.com/nedbat/coveragepy/compare/7.6.12...7.7.0)

Updates `mkdocs-material` from 9.6.7 to 9.6.8
- [Release notes](https://github.com/squidfunk/mkdocs-material/releases)
- [Changelog](https://github.com/squidfunk/mkdocs-material/blob/master/CHANGELOG)
- [Commits](https://github.com/squidfunk/mkdocs-material/compare/9.6.7...9.6.8)

Updates `mkdocstrings` from 0.28.3 to 0.29.0
- [Release notes](https://github.com/mkdocstrings/mkdocstrings/releases)
- [Changelog](https://github.com/mkdocstrings/mkdocstrings/blob/main/CHANGELOG.md)
- [Commits](https://github.com/mkdocstrings/mkdocstrings/compare/0.28.3...0.29.0)

Updates `mkdocstrings-python` from 1.16.3 to 1.16.5
- [Release notes](https://github.com/mkdocstrings/python/releases)
- [Changelog](https://github.com/mkdocstrings/python/blob/main/CHANGELOG.md)
- [Commits](https://github.com/mkdocstrings/python/compare/1.16.3...1.16.5)

---
updated-dependencies:
- dependency-name: ruff
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: all
- dependency-name: coverage
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: all
- dependency-name: mkdocs-material
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: mkdocstrings
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: all
- dependency-name: mkdocstrings-python
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: all
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-17 08:44:26 +10:00
Firstyear
b88b6923eb
20250313 unixd system cache (#3501)
The implementation of the unixd cache relies on inotify to detect changes to files in /etc so that we know when to reload the data for nss/passwd. However, the way that groupadd/del and other tools work is they copy the file, change it, and then move it into place. It turns out that william of the past didn't realise that inotify works on inodes not paths like other tools do (auditctl for example).

As a result, when something modified /etc/group or another related file, the removal was seen, but this breaks notifications on any future change until you reload unixd.

To resolve this we need to recursively watch /etc with inotify - yep, that's correct. We have to watch everything in /etc for changes because it's the only way to pick up on the add/remove of files. But because we have to watch everything, we need permissions to watch everything.

This forces us to move the parsing of the etc passwd/group/shadow files to the unixd tasks daemon - arguably, this is the correct place to read these anyway since that is a high priv (and locked down) daemon. Because of this, we actually end up solving the missing "shadow" group on debian issue, and probably similar on the BSD's in future.

In order to make my life easier while testing I also threw in a makefile that symlinks the files to needed locations for testing. It has plenty of warnings as it should.

Fixes #3499
Fixes #3407
Fixes #3249
2025-03-14 13:46:26 +10:00
Firstyear
e3243ce6b0
Support rfc2307 memberUid in sync operations. (#3466)
A lot of legacy directory servers will use rfc2307 schema where
members of groups are stored as the uid instead of a dn. Within
kani, we absolutely need this to be a dn, else we risk accidentally
adding kanidm entries into ldap synced groups which isn't what we
want.

If we have an rfc2307 schema, then we pre-resolve the uid to the
member dn so that kanidm gets the correct information.
2025-03-14 00:48:05 +00:00
dependabot[bot]
4b4e690642
Bump mozilla-actions/sccache-action from 0.0.7 to 0.0.8 in the all group (#3496)
* Bump mozilla-actions/sccache-action from 0.0.7 to 0.0.8 in the all group
* fix: remove manual specification of sccache version from github actions

Bumps the all group with 1 update: [mozilla-actions/sccache-action](https://github.com/mozilla-actions/sccache-action).


Updates `mozilla-actions/sccache-action` from 0.0.7 to 0.0.8
- [Release notes](https://github.com/mozilla-actions/sccache-action/releases)
- [Commits](https://github.com/mozilla-actions/sccache-action/compare/v0.0.7...v0.0.8)

---
updated-dependencies:
- dependency-name: mozilla-actions/sccache-action
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-14 00:32:14 +00:00
Jason
d6549077fb
Update Traefik config example to remove invalid label (#3500)
Remove non-existent traefik label config
2025-03-13 04:36:02 +00:00
Firstyear
2c5ce227ae
Add uid/gid allocation table (#3498) 2025-03-11 06:42:08 +00:00
Firstyear
919e0ba6fe
20250225 ldap testing in testkit (#3460)
Add support for ldap servers in integration tests

This allows the ldap interface to be enabled during tests, which is
a final requirement to complete ldap application passwords.
2025-03-11 12:35:31 +10:00
dependabot[bot]
23d35dc324
Bump the all group in /pykanidm with 5 updates (#3494)
Bumps the all group in /pykanidm with 5 updates:

| Package | From | To |
| --- | --- | --- |
| [ruff](https://github.com/astral-sh/ruff) | `0.9.9` | `0.9.10` |
| [types-requests](https://github.com/python/typeshed) | `2.32.0.20250301` | `2.32.0.20250306` |
| [mkdocs-material](https://github.com/squidfunk/mkdocs-material) | `9.6.6` | `9.6.7` |
| [mkdocstrings](https://github.com/mkdocstrings/mkdocstrings) | `0.28.2` | `0.28.3` |
| [mkdocstrings-python](https://github.com/mkdocstrings/python) | `1.16.2` | `1.16.3` |


Updates `ruff` from 0.9.9 to 0.9.10
- [Release notes](https://github.com/astral-sh/ruff/releases)
- [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md)
- [Commits](https://github.com/astral-sh/ruff/compare/0.9.9...0.9.10)

Updates `types-requests` from 2.32.0.20250301 to 2.32.0.20250306
- [Commits](https://github.com/python/typeshed/commits)

Updates `mkdocs-material` from 9.6.6 to 9.6.7
- [Release notes](https://github.com/squidfunk/mkdocs-material/releases)
- [Changelog](https://github.com/squidfunk/mkdocs-material/blob/master/CHANGELOG)
- [Commits](https://github.com/squidfunk/mkdocs-material/compare/9.6.6...9.6.7)

Updates `mkdocstrings` from 0.28.2 to 0.28.3
- [Release notes](https://github.com/mkdocstrings/mkdocstrings/releases)
- [Changelog](https://github.com/mkdocstrings/mkdocstrings/blob/main/CHANGELOG.md)
- [Commits](https://github.com/mkdocstrings/mkdocstrings/compare/0.28.2...0.28.3)

Updates `mkdocstrings-python` from 1.16.2 to 1.16.3
- [Release notes](https://github.com/mkdocstrings/python/releases)
- [Changelog](https://github.com/mkdocstrings/python/blob/main/CHANGELOG.md)
- [Commits](https://github.com/mkdocstrings/python/compare/1.16.2...1.16.3)

---
updated-dependencies:
- dependency-name: ruff
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: types-requests
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: mkdocs-material
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: mkdocstrings
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: mkdocstrings-python
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: all
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-11 08:49:13 +10:00
dependabot[bot]
7d9661ef45
Bump ring from 0.17.10 to 0.17.13 in the cargo group (#3491)
Bumps the cargo group with 1 update: [ring](https://github.com/briansmith/ring).


Updates `ring` from 0.17.10 to 0.17.13
- [Changelog](https://github.com/briansmith/ring/blob/main/RELEASES.md)
- [Commits](https://github.com/briansmith/ring/commits)

---
updated-dependencies:
- dependency-name: ring
  dependency-type: indirect
  dependency-group: cargo
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-09 11:53:42 +10:00
Firstyear
dcd5cd23f4
Handle form-post as a response mode (#3467)
Some oauth2 clients apparently ignore what we tell them
and request response modes we don't support.

First, we should deserialise these and error correctly.

Second, to maintain temporary compatibility, we remap
form-post to query. This will be removed in future.
2025-03-05 13:21:09 +10:00
Tshepang Mbambo
7b2bd38ab2
book: fix english (#3487)
* fix Python docs wording

---------

Co-authored-by: James Hodgkinson <james@terminaloutcomes.com>
2025-03-04 21:16:00 +00:00
Firstyear
775dd520cb
Correct paths with Kanidm Tools Container (#3486) 2025-03-04 14:52:30 +10:00
Firstyear
63deda350c
20250225 improve test performance (#3459)
* Ignore tests that are no longer used.

Each time a library or binary is added, that requires compilation to create
the *empty* test harness, which then is executed and takes multiple seconds
to start up, do nothing, and return success.

This removes test's for libraries that aren't actually using or running
any tests.

Additionally, each time a new test binary is added, that adds a ton of
compilation time, but also test execution time as the binary for each
test runner must start up, execute, and shutdown. So this merges all
the testkit integration tests to a single running which significantly
speeds up test execution.

* Improve IDL exists behaviour, improve memberof verification

Again to improve test performance. This improves the validation of idx
existance to be a faster SQLite call, caches the results as needed.

Memberof was taking up a large amount of time in verify phases of test
finalisation, and so a better in memory version has been added.

* Disable TLS native roots when not needed

* Cleanup tests that are hitting native certs, or do nothing at all
2025-03-04 10:36:53 +10:00
dependabot[bot]
7eedb0159f
Bump the all group in /pykanidm with 8 updates (#3484)
---
updated-dependencies:
- dependency-name: aiohttp
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: authlib
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: all
- dependency-name: ruff
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: pytest
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: types-requests
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: mkdocs-material
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: mkdocstrings
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: mkdocstrings-python
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: all
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-03 08:00:57 +10:00
Firstyear
e98d60a962
Use lld by default on linux (#3477)
* Use lld by default on linux

---------

Co-authored-by: James Hodgkinson <james@terminaloutcomes.com>
2025-02-28 08:30:59 +00:00
Firstyear
25c1c1573e
20250213 patch used wrong acp (#3432)
Migrations and server bootstrap are very interconnected processes
and in this we'll be addressing and improving both.

Server bootstrap was performed by creating base entries in phases,
eventually bringing up enough of the *oldest* supported server
minimum remigration level, to then allow triggering of migrations.

Migrations then applied "patches" effectively ontop of this minimum
level to update entries to what they should be in newer versions of
the server.

This scheme has it's pros and cons, but the major con was that to
remove a migration meant squashing it's content back into the
minimum remigration level, and this was a human process that was
quite error prone and difficult to automate. As well, this scheme
also led to cases where the patch migrations would sometimes *not*
reflect all the needed changes or content, or in one case was actually
undone by a patchlevel fix up that was required to address a bug.

Invariably this led to issues, and cases where a new server may have
different content to a migrated one - not exactly what we want!

This is a new migration scheme that addresses this fragility. However
what it trades is verbosity of the content.

Rather than having a base set of entries and patching/updating small
sections ontop, we have migration data folders that contain the full
set of entries as they should appear at that migration level. This
makes the bootstrap process easier as we can just apply the migration
level as a whole, and targetted to what precise version we want.

This also makes migrations more durable as the content is explicitly
copied and all entries fully applied, so there is no risk that a
migration or data change can be forgotten or applied incorrectly. We
are expressing the full state of what our builtin and provided entries
should be.

Finally this rips out a number of places where migration data was being
used as test case data. Not all of these have been replaced (notably
in authsession with Account), but the majority have and have been replaced
with clearer use of constants rather than building whole entries just to
access the name and throw them away for example.
2025-02-28 10:18:48 +10:00
Ludea
145ffed7c6
Android support (#3475) 2025-02-27 11:45:33 +00:00
CEbbinghaus
b669f38d23
Changed all CI/CD builds to locked (#3471) 2025-02-26 22:04:23 +00:00
Firstyear
537d6fd93b
Make it a bit clearer that providers are needed (#3468) 2025-02-27 00:05:33 +10:00
Firstyear
b6ffb31e4a
Fix incorrect credential generation in radius docs (#3465) 2025-02-26 12:03:10 +10:00
Firstyear
0e0e8ff844
Add crypt formats for password import (#3458)
Adds crypt md5, sha256 and sha512 allowing import of legacy credentials
from external ldap servers.
2025-02-25 11:09:34 +00:00
Jade Ellis
266dc77536
build: Create daemon image from scratch (#3452) 2025-02-25 14:16:08 +10:00
micolous
3edee485dd
address webfinger doc feedbacks (#3446) 2025-02-25 02:53:53 +00:00
dependabot[bot]
38c260214b
Bump the all group across 1 directory with 5 updates (#3453)
Bumps the all group with 5 updates in the /pykanidm directory:

| Package | From | To |
| --- | --- | --- |
| [ruff](https://github.com/astral-sh/ruff) | `0.9.5` | `0.9.7` |
| [coverage](https://github.com/nedbat/coveragepy) | `7.6.11` | `7.6.12` |
| [mkdocs-material](https://github.com/squidfunk/mkdocs-material) | `9.6.3` | `9.6.5` |
| [mkdocstrings](https://github.com/mkdocstrings/mkdocstrings) | `0.28.0` | `0.28.1` |
| [mkdocstrings-python](https://github.com/mkdocstrings/python) | `1.14.6` | `1.16.1` |



Updates `ruff` from 0.9.5 to 0.9.7
- [Release notes](https://github.com/astral-sh/ruff/releases)
- [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md)
- [Commits](https://github.com/astral-sh/ruff/compare/0.9.5...0.9.7)

Updates `coverage` from 7.6.11 to 7.6.12
- [Release notes](https://github.com/nedbat/coveragepy/releases)
- [Changelog](https://github.com/nedbat/coveragepy/blob/master/CHANGES.rst)
- [Commits](https://github.com/nedbat/coveragepy/compare/7.6.11...7.6.12)

Updates `mkdocs-material` from 9.6.3 to 9.6.5
- [Release notes](https://github.com/squidfunk/mkdocs-material/releases)
- [Changelog](https://github.com/squidfunk/mkdocs-material/blob/master/CHANGELOG)
- [Commits](https://github.com/squidfunk/mkdocs-material/compare/9.6.3...9.6.5)

Updates `mkdocstrings` from 0.28.0 to 0.28.1
- [Release notes](https://github.com/mkdocstrings/mkdocstrings/releases)
- [Changelog](https://github.com/mkdocstrings/mkdocstrings/blob/main/CHANGELOG.md)
- [Commits](https://github.com/mkdocstrings/mkdocstrings/compare/0.28.0...0.28.1)

Updates `mkdocstrings-python` from 1.14.6 to 1.16.1
- [Release notes](https://github.com/mkdocstrings/python/releases)
- [Changelog](https://github.com/mkdocstrings/python/blob/main/CHANGELOG.md)
- [Commits](https://github.com/mkdocstrings/python/compare/1.14.6...1.16.1)

---
updated-dependencies:
- dependency-name: ruff
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: coverage
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: mkdocs-material
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: mkdocstrings
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: mkdocstrings-python
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: all
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-24 13:22:51 +10:00
Merlijn
857dcf5087
[htmx] Admin ui for groups and users management (#3019)
* Some progress on admin ui for managing groups and users
* Improve scim querying

---------

Co-authored-by: William Brown <william@blackhats.net.au>
2025-02-22 13:43:54 +10:00
Sebastiano Tocci
9611a7f976
Fixes #3406: add configurable maximum queryable attributes for LDAP (#3431) 2025-02-21 12:14:47 +10:00
sinavir
f40679cd52
Accept invalid certs and fix token_cache_path (#3439)
* Add accept-invalid-certs option for cli
* Fix token_cache_path behavior

---------

Co-authored-by: sinavir <sinavir@sinavir.fr>
2025-02-20 08:07:48 +00:00
Firstyear
52824b58f1
Accept lowercase ldap pwd hashes (#3444) 2025-02-20 04:34:27 +00:00
CEbbinghaus
848af4cecd
TOTP label verification (#3419)
* Adding TOTP Label verification (for both empty and duplicate)
2025-02-19 06:54:50 +00:00
micolous
de506a5f53
Rewrite WebFinger docs (#3443) 2025-02-19 12:26:15 +10:00
micolous
7f3b1f2580
doc: fix formatting of URL table, remove Caddyfile instructions (#3442)
There are many web servers, and this breaks the flow of the rest of the table.
2025-02-19 11:18:58 +10:00
Alex Martens
9bf17c4846
book: add OAuth2 Proxy example (#3434) 2025-02-16 05:14:47 +00:00
Firstyear
ed88b72080
Exempt idm_admin and admin from denied names. (#3429)
idm_admin and admin should be exempted from the denied names process,
as these values will already be denied due to attribute uniqueness.
Additionally improved the denied names check to only validate the
name during a change, not during a modifification. This way entries
that become denied can get themself out of the pickle.
2025-02-15 22:45:25 +00:00
Firstyear
d0b0b163fd
Book fixes (#3433) 2025-02-15 16:01:44 +10:00
Jade Ellis
ce410f440c
ci: uniform Docker builds (#3430) 2025-02-14 10:25:04 +00:00
Firstyear
77271c1720
20240213 3413 domain displayname (#3425)
Remove older migrations and make domain displayname optional.
2025-02-14 10:52:49 +10:00
Justin Warren
e838da9a08
Correct path to kanidm config example in documentation. (#3424) 2025-02-13 01:31:38 +00:00
Firstyear
94b7285cbb
Support redirect uris with query parameters (#3422)
RFC 6749 once again reminds us that given the room to do silly
things, RFC authors absolutely will. In this case, it's query
parameters in redirection uris which are absolutely horrifying
and yet, here we are.

We strictly match the query pairs during the redirection to
ensure that if a query pair did allow open redirection, then
we prevent it.
2025-02-13 01:03:15 +00:00
Firstyear
af6f55b1fe
Update to 1.6.0-dev (#3418) 2025-02-11 07:26:07 +00:00
George Wu
211e7d4e89
Remove white background from square logo. (#3417) 2025-02-11 14:41:55 +10:00
CEbbinghaus
ccde675cd2
feat: Added webfinger implementation (#3410)
Adds WebFinger endpoints to every oauth2 client

Co-authored-by: James Hodgkinson <james@terminaloutcomes.com>
2025-02-10 06:10:12 +00:00
dependabot[bot]
b96fe49b99
Bump the all group in /pykanidm with 7 updates (#3412)
Bumps the all group in /pykanidm with 7 updates:

| Package | From | To |
| --- | --- | --- |
| [aiohttp](https://github.com/aio-libs/aiohttp) | `3.11.11` | `3.11.12` |
| [ruff](https://github.com/astral-sh/ruff) | `0.9.4` | `0.9.5` |
| [mypy](https://github.com/python/mypy) | `1.14.1` | `1.15.0` |
| [coverage](https://github.com/nedbat/coveragepy) | `7.6.10` | `7.6.11` |
| [mkdocs-material](https://github.com/squidfunk/mkdocs-material) | `9.6.1` | `9.6.3` |
| [mkdocstrings](https://github.com/mkdocstrings/mkdocstrings) | `0.27.0` | `0.28.0` |
| [mkdocstrings-python](https://github.com/mkdocstrings/python) | `1.13.0` | `1.14.6` |


Updates `aiohttp` from 3.11.11 to 3.11.12
- [Release notes](https://github.com/aio-libs/aiohttp/releases)
- [Changelog](https://github.com/aio-libs/aiohttp/blob/master/CHANGES.rst)
- [Commits](https://github.com/aio-libs/aiohttp/compare/v3.11.11...v3.11.12)

Updates `ruff` from 0.9.4 to 0.9.5
- [Release notes](https://github.com/astral-sh/ruff/releases)
- [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md)
- [Commits](https://github.com/astral-sh/ruff/compare/0.9.4...0.9.5)

Updates `mypy` from 1.14.1 to 1.15.0
- [Changelog](https://github.com/python/mypy/blob/master/CHANGELOG.md)
- [Commits](https://github.com/python/mypy/compare/v1.14.1...v1.15.0)

Updates `coverage` from 7.6.10 to 7.6.11
- [Release notes](https://github.com/nedbat/coveragepy/releases)
- [Changelog](https://github.com/nedbat/coveragepy/blob/master/CHANGES.rst)
- [Commits](https://github.com/nedbat/coveragepy/compare/7.6.10...7.6.11)

Updates `mkdocs-material` from 9.6.1 to 9.6.3
- [Release notes](https://github.com/squidfunk/mkdocs-material/releases)
- [Changelog](https://github.com/squidfunk/mkdocs-material/blob/master/CHANGELOG)
- [Commits](https://github.com/squidfunk/mkdocs-material/compare/9.6.1...9.6.3)

Updates `mkdocstrings` from 0.27.0 to 0.28.0
- [Release notes](https://github.com/mkdocstrings/mkdocstrings/releases)
- [Changelog](https://github.com/mkdocstrings/mkdocstrings/blob/main/CHANGELOG.md)
- [Commits](https://github.com/mkdocstrings/mkdocstrings/compare/0.27.0...0.28.0)

Updates `mkdocstrings-python` from 1.13.0 to 1.14.6
- [Release notes](https://github.com/mkdocstrings/python/releases)
- [Changelog](https://github.com/mkdocstrings/python/blob/main/CHANGELOG.md)
- [Commits](https://github.com/mkdocstrings/python/compare/1.13.0...1.14.6)

---
updated-dependencies:
- dependency-name: aiohttp
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: ruff
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: mypy
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: all
- dependency-name: coverage
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: mkdocs-material
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: mkdocstrings
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: all
- dependency-name: mkdocstrings-python
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: all
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-10 07:19:22 +10:00
James Hodgkinson
c89f0c011e
20250209 pre release (#3409)
* fix: removing unused dependencies (assert_cmd, gethostname)
* chore: Release Notes
2025-02-09 10:06:01 +00:00
Firstyear
b15ff89b39
20250206 freebsd ports (#3404)
* Remove unneeded files
* Ensure we config client config for freebsd
* Improve shell handling
* Use freebsd compat nss
2025-02-09 08:57:15 +00:00
Firstyear
1f5ce2617d
Resolve kanidm-unix auth-test bug (#3405)
* Resolve kanidm-unix auth-test bug

When reworking the unix daemon, we missed changing the auth-test
tool to handle the new challenge-response flow correctly which
would cause the session to disconnect.

* Cleanup
2025-02-09 02:49:54 +00:00
CEbbinghaus
f68906bf1b
chore: Remove empty scopemaps (#3170) 2025-02-09 11:19:52 +10:00
CEbbinghaus
7a9bb9eac2
Feat: Allowing spn query with non-spn structured data in LDAP (#3400)
* Added Botch for fixing spn query

* Got Invalid filter working. spn can now be searched on

* Addressed review comments

* Resolved Invalid filter correctly for no index

* Cleaned comments and added tests (still 1 failing)

* Added comments and fixed unit test

* Formatting

* Made Clippy Happy
2025-02-08 06:37:28 +00:00
Wei Jian Gan
0ce1bbeddc
SSH Keys in Credentials Update (#3027) 2025-02-08 11:54:41 +10:00
Firstyear
ad3cf8828f
20250205 3369 firefox pin (#3403)
Improve error message when passkey is missing PIN

Firefox still doesn't support setting a PIN on new devices. Because
of this we need a way to return a better error message for devices
that don't have UV configured.
2025-02-06 00:33:59 +00:00
Firstyear
43b7f80535
Correctly return that uuid2spn changed on domain rename (#3402)
Due to a missing equality check in value, when a domain
rename occured, the uuid2spn index differential function
did not correctly detect that the domain name had updated
which meant that the uuid2spn index was not updated. Only
this index was affected, and a manual reindex would
resolve.
2025-02-06 08:50:45 +10:00
Firstyear
41b2eac1f4
Fix the password reset form and possible resolver issue (#3398)
While testing for everything open I noticed two possible
issues. This PR fixes both.

The first is a possible recursion in the resolver. I think
I need to fix up it's transactions a bit in another PR.

The second was that the submit button on the reset form
doesn't work. This fixes that as well as post reset redirecting
to the correct location.
2025-02-05 14:18:09 +10:00
James
4938c6796b
Add handle_group_error to cli client (#3399)
Closes #2616
2025-02-05 02:52:20 +00:00
Firstyear
9c2825b9dc
Improve spans in unixd (#3397)
Some areas of the code were emitting 0 uuids, rather than associating
a client/connection uuid. This improves the startup and client handling
code so that we have stable uuids present during operation.
2025-02-05 01:33:30 +00:00
Firstyear
9505b5a732
Allow OAuth2 with empty state parameter (#3396) 2025-02-05 00:39:53 +00:00
James Hodgkinson
3b3c029e30
#3387 - RADIUS Startup fixin's (#3388)
* fix: outdated poetry.toml entries
* fix: better handling errors on startup in radius_entrypoint
* fix: radiusd eap config, removing dh_file per error message in freeradius startup
* fix: updating docs to be a little clearer and reflect new config
* fix: fixing up handling dhparam, trying to throw better errors
* fix: unified how the config path is found in pykanidm radius, new default config path

---------

Co-authored-by: Firstyear <william@blackhats.net.au>
2025-02-04 09:30:25 +00:00
Jason
99e37e987a
Allow POST on oauth userinfo (#3395) 2025-02-04 06:22:32 +00:00
Andris Raugulis
d4c5a6f4a9
OpenBSD support (#3381)
* Implement OpenBSD support.
2025-02-03 22:39:50 +00:00
dependabot[bot]
d3457ff3c1
Bump openssl from 0.10.69 to 0.10.70 in the cargo group (#3391)
Bumps the cargo group with 1 update: [openssl](https://github.com/sfackler/rust-openssl).


Updates `openssl` from 0.10.69 to 0.10.70
- [Release notes](https://github.com/sfackler/rust-openssl/releases)
- [Commits](https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.69...openssl-v0.10.70)

---
updated-dependencies:
- dependency-name: openssl
  dependency-type: direct:production
  dependency-group: cargo
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-04 08:21:03 +10:00
James
f93d07b6cc
Add /.well-known/change-password endpoint (#3382)
* feat: Add /.well-known/change-password endpoint
* fix: make the https view constants available inside the crate

---------
Co-authored-by: James Hodgkinson <james@terminaloutcomes.com>
2025-02-03 00:57:05 +00:00
dependabot[bot]
351fdcdef0
Bump the all group across 1 directory with 7 updates (#3385)
Bumps the all group with 7 updates in the /pykanidm directory:

| Package | From | To |
| --- | --- | --- |
| [pydantic](https://github.com/pydantic/pydantic) | `2.10.5` | `2.10.6` |
| [authlib](https://github.com/lepture/authlib) | `1.4.0` | `1.4.1` |
| [pytest-asyncio](https://github.com/pytest-dev/pytest-asyncio) | `0.25.2` | `0.25.3` |
| [pytest-aiohttp](https://github.com/aio-libs/pytest-aiohttp) | `1.0.5` | `1.1.0` |
| [black](https://github.com/psf/black) | `24.10.0` | `25.1.0` |
| [mkdocs-material](https://github.com/squidfunk/mkdocs-material) | `9.5.50` | `9.6.1` |
| [ruff](https://github.com/astral-sh/ruff) | `0.9.2` | `0.9.4` |



Updates `pydantic` from 2.10.5 to 2.10.6
- [Release notes](https://github.com/pydantic/pydantic/releases)
- [Changelog](https://github.com/pydantic/pydantic/blob/main/HISTORY.md)
- [Commits](https://github.com/pydantic/pydantic/compare/v2.10.5...v2.10.6)

Updates `authlib` from 1.4.0 to 1.4.1
- [Release notes](https://github.com/lepture/authlib/releases)
- [Changelog](https://github.com/lepture/authlib/blob/master/docs/changelog.rst)
- [Commits](https://github.com/lepture/authlib/compare/v1.4.0...v1.4.1)

Updates `pytest-asyncio` from 0.25.2 to 0.25.3
- [Release notes](https://github.com/pytest-dev/pytest-asyncio/releases)
- [Commits](https://github.com/pytest-dev/pytest-asyncio/compare/v0.25.2...v0.25.3)

Updates `pytest-aiohttp` from 1.0.5 to 1.1.0
- [Release notes](https://github.com/aio-libs/pytest-aiohttp/releases)
- [Changelog](https://github.com/aio-libs/pytest-aiohttp/blob/master/CHANGES.rst)
- [Commits](https://github.com/aio-libs/pytest-aiohttp/compare/v1.0.5...v1.1.0)

Updates `black` from 24.10.0 to 25.1.0
- [Release notes](https://github.com/psf/black/releases)
- [Changelog](https://github.com/psf/black/blob/main/CHANGES.md)
- [Commits](https://github.com/psf/black/compare/24.10.0...25.1.0)

Updates `mkdocs-material` from 9.5.50 to 9.6.1
- [Release notes](https://github.com/squidfunk/mkdocs-material/releases)
- [Changelog](https://github.com/squidfunk/mkdocs-material/blob/master/CHANGELOG)
- [Commits](https://github.com/squidfunk/mkdocs-material/compare/9.5.50...9.6.1)

Updates `ruff` from 0.9.2 to 0.9.4
- [Release notes](https://github.com/astral-sh/ruff/releases)
- [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md)
- [Commits](https://github.com/astral-sh/ruff/compare/0.9.2...0.9.4)

---
updated-dependencies:
- dependency-name: pydantic
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: authlib
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: pytest-asyncio
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: pytest-aiohttp
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: all
- dependency-name: black
  dependency-type: direct:development
  update-type: version-update:semver-major
  dependency-group: all
- dependency-name: mkdocs-material
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: all
- dependency-name: ruff
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: all
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-03 09:05:30 +11:00
Fabian Kammel
1453ba5d74
extend oauth2 examples with gitea (#3351)
* extend oauth2 examples with gitea
* add myself to contributors

---------

Signed-off-by: Fabian Kammel <fabian@kammel.dev>
Co-authored-by: James Hodgkinson <james@terminaloutcomes.com>
2025-01-29 05:41:03 +00:00
dependabot[bot]
ed76bdbfb1
Bump the all group with 22 updates (#3376)
* Bump the all group with 22 updates

Bumps the all group with 22 updates:

| Package | From | To |
| --- | --- | --- |
| [async-trait](https://github.com/dtolnay/async-trait) | `0.1.83` | `0.1.85` |
| [bitflags](https://github.com/bitflags/bitflags) | `2.6.0` | `2.8.0` |
| [clap](https://github.com/clap-rs/clap) | `4.5.23` | `4.5.27` |
| [clap_complete](https://github.com/clap-rs/clap) | `4.5.40` | `4.5.42` |
| [lodepng](https://github.com/kornelski/lodepng-rust) | `3.10.7` | `3.11.0` |
| [openssl](https://github.com/sfackler/rust-openssl) | `0.10.68` | `0.10.69` |
| [proc-macro2](https://github.com/dtolnay/proc-macro2) | `1.0.92` | `1.0.93` |
| [reqwest](https://github.com/seanmonstar/reqwest) | `0.12.11` | `0.12.12` |
| [rustls](https://github.com/rustls/rustls) | `0.23.20` | `0.23.21` |
| [sd-notify](https://github.com/lnicola/sd-notify) | `0.4.4` | `0.4.5` |
| [serde_json](https://github.com/serde-rs/json) | `1.0.134` | `1.0.137` |
| [syn](https://github.com/dtolnay/syn) | `2.0.93` | `2.0.96` |
| [tempfile](https://github.com/Stebalien/tempfile) | `3.14.0` | `3.15.0` |
| [tokio](https://github.com/tokio-rs/tokio) | `1.42.0` | `1.43.0` |
| [uuid](https://github.com/uuid-rs/uuid) | `1.11.0` | `1.12.1` |
| [oauth2](https://github.com/ramosbugs/oauth2-rs) | `4.4.2` | `5.0.0` |
| [cc](https://github.com/rust-lang/cc-rs) | `1.2.6` | `1.2.10` |
| [axum-extra](https://github.com/tokio-rs/axum) | `0.9.6` | `0.10.0` |
| [axum-macros](https://github.com/tokio-rs/axum) | `0.4.2` | `0.5.0` |
| [fantoccini](https://github.com/jonhoo/fantoccini) | `0.21.3` | `0.21.4` |
| [petgraph](https://github.com/petgraph/petgraph) | `0.6.5` | `0.7.1` |
| [jsonschema](https://github.com/Stranger6667/jsonschema) | `0.28.0` | `0.28.3` |


Updates `async-trait` from 0.1.83 to 0.1.85
- [Release notes](https://github.com/dtolnay/async-trait/releases)
- [Commits](https://github.com/dtolnay/async-trait/compare/0.1.83...0.1.85)

Updates `bitflags` from 2.6.0 to 2.8.0
- [Release notes](https://github.com/bitflags/bitflags/releases)
- [Changelog](https://github.com/bitflags/bitflags/blob/main/CHANGELOG.md)
- [Commits](https://github.com/bitflags/bitflags/compare/2.6.0...2.8.0)

Updates `clap` from 4.5.23 to 4.5.27
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/clap_complete-v4.5.23...clap_complete-v4.5.27)

Updates `clap_complete` from 4.5.40 to 4.5.42
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/clap_complete-v4.5.40...clap_complete-v4.5.42)

Updates `lodepng` from 3.10.7 to 3.11.0
- [Commits](https://github.com/kornelski/lodepng-rust/compare/v3.10.7...v3.11.0)

Updates `openssl` from 0.10.68 to 0.10.69
- [Release notes](https://github.com/sfackler/rust-openssl/releases)
- [Commits](https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.68...openssl-v0.10.69)

Updates `proc-macro2` from 1.0.92 to 1.0.93
- [Release notes](https://github.com/dtolnay/proc-macro2/releases)
- [Commits](https://github.com/dtolnay/proc-macro2/compare/1.0.92...1.0.93)

Updates `reqwest` from 0.12.11 to 0.12.12
- [Release notes](https://github.com/seanmonstar/reqwest/releases)
- [Changelog](https://github.com/seanmonstar/reqwest/blob/master/CHANGELOG.md)
- [Commits](https://github.com/seanmonstar/reqwest/compare/v0.12.11...v0.12.12)

Updates `rustls` from 0.23.20 to 0.23.21
- [Release notes](https://github.com/rustls/rustls/releases)
- [Changelog](https://github.com/rustls/rustls/blob/main/CHANGELOG.md)
- [Commits](https://github.com/rustls/rustls/compare/v/0.23.20...v/0.23.21)

Updates `sd-notify` from 0.4.4 to 0.4.5
- [Changelog](https://github.com/lnicola/sd-notify/blob/master/CHANGELOG.md)
- [Commits](https://github.com/lnicola/sd-notify/compare/v0.4.4...v0.4.5)

Updates `serde_json` from 1.0.134 to 1.0.137
- [Release notes](https://github.com/serde-rs/json/releases)
- [Commits](https://github.com/serde-rs/json/compare/v1.0.134...v1.0.137)

Updates `syn` from 2.0.93 to 2.0.96
- [Release notes](https://github.com/dtolnay/syn/releases)
- [Commits](https://github.com/dtolnay/syn/compare/2.0.93...2.0.96)

Updates `tempfile` from 3.14.0 to 3.15.0
- [Changelog](https://github.com/Stebalien/tempfile/blob/master/CHANGELOG.md)
- [Commits](https://github.com/Stebalien/tempfile/compare/v3.14.0...v3.15.0)

Updates `tokio` from 1.42.0 to 1.43.0
- [Release notes](https://github.com/tokio-rs/tokio/releases)
- [Commits](https://github.com/tokio-rs/tokio/compare/tokio-1.42.0...tokio-1.43.0)

Updates `uuid` from 1.11.0 to 1.12.1
- [Release notes](https://github.com/uuid-rs/uuid/releases)
- [Commits](https://github.com/uuid-rs/uuid/compare/1.11.0...1.12.1)

Updates `oauth2` from 4.4.2 to 5.0.0
- [Release notes](https://github.com/ramosbugs/oauth2-rs/releases)
- [Upgrade guide](https://github.com/ramosbugs/oauth2-rs/blob/main/UPGRADE.md)
- [Commits](https://github.com/ramosbugs/oauth2-rs/compare/4.4.2...5.0.0)

Updates `cc` from 1.2.6 to 1.2.10
- [Release notes](https://github.com/rust-lang/cc-rs/releases)
- [Changelog](https://github.com/rust-lang/cc-rs/blob/main/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/cc-rs/compare/cc-v1.2.6...cc-v1.2.10)

Updates `axum-extra` from 0.9.6 to 0.10.0
- [Release notes](https://github.com/tokio-rs/axum/releases)
- [Changelog](https://github.com/tokio-rs/axum/blob/main/CHANGELOG.md)
- [Commits](https://github.com/tokio-rs/axum/compare/axum-extra-v0.9.6...axum-extra-v0.10.0)

Updates `axum-macros` from 0.4.2 to 0.5.0
- [Release notes](https://github.com/tokio-rs/axum/releases)
- [Changelog](https://github.com/tokio-rs/axum/blob/main/CHANGELOG.md)
- [Commits](https://github.com/tokio-rs/axum/compare/axum-macros-v0.4.2...axum-macros-v0.5.0)

Updates `fantoccini` from 0.21.3 to 0.21.4
- [Commits](https://github.com/jonhoo/fantoccini/compare/v0.21.3...v0.21.4)

Updates `petgraph` from 0.6.5 to 0.7.1
- [Changelog](https://github.com/petgraph/petgraph/blob/master/RELEASES.rst)
- [Commits](https://github.com/petgraph/petgraph/compare/petgraph@v0.6.5...petgraph@v0.7.1)

Updates `jsonschema` from 0.28.0 to 0.28.3
- [Release notes](https://github.com/Stranger6667/jsonschema/releases)
- [Changelog](https://github.com/Stranger6667/jsonschema/blob/master/CHANGELOG.md)
- [Commits](https://github.com/Stranger6667/jsonschema/compare/rust-v0.28.0...rust-v0.28.3)

---
updated-dependencies:
- dependency-name: async-trait
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: bitflags
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: all
- dependency-name: clap
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: clap_complete
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: lodepng
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: all
- dependency-name: openssl
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: proc-macro2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: reqwest
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: rustls
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: sd-notify
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: serde_json
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: syn
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: tempfile
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: all
- dependency-name: tokio
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: all
- dependency-name: uuid
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: all
- dependency-name: oauth2
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: all
- dependency-name: cc
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: axum-extra
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: all
- dependency-name: axum-macros
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: all
- dependency-name: fantoccini
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: petgraph
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: all
- dependency-name: jsonschema
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all
...

Signed-off-by: dependabot[bot] <support@github.com>

* ok the otel stuff works now

* linting fixes

* fix: less parse more from_str, adding a todo

* fix: removing a TODO

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: James Hodgkinson <james@terminaloutcomes.com>
2025-01-29 13:57:38 +10:00
CEbbinghaus
12532ee32d
Book: Added small section on primary cred fallback (#3365) 2025-01-21 09:45:06 +00:00
CEbbinghaus
10f03e19c0
Added shell.nix to create dev environment (#3362) 2025-01-21 09:26:43 +00:00
George Wu
c324fa92f5
fix(ci): Add setup-oras step to include ORAS CLI for container builds on ubuntu-24.04. (#3368) 2025-01-21 09:43:26 +13:00
Firstyear
b3be758b74
20250114 3325 SCIM access control (#3359)
Add an extended query operation to return effective access controls so that UI's can dynamically display what is or is not editable on an entry.
2025-01-20 11:28:22 +00:00
George Wu
b03f842728
Small UI updates. (#3361)
* Delete unused htmx javascript files.

* Consistently mention applications instead of apps.

* Small formatting change for enrol device.

* Update phrasing in credentials page.
2025-01-20 04:52:53 +00:00
dependabot[bot]
27cc31dace
Bump the all group in /pykanidm with 2 updates (#3366)
Bumps the all group in /pykanidm with 2 updates: [mkdocs-material](https://github.com/squidfunk/mkdocs-material) and [ruff](https://github.com/astral-sh/ruff).


Updates `mkdocs-material` from 9.5.49 to 9.5.50
- [Release notes](https://github.com/squidfunk/mkdocs-material/releases)
- [Changelog](https://github.com/squidfunk/mkdocs-material/blob/master/CHANGELOG)
- [Commits](https://github.com/squidfunk/mkdocs-material/compare/9.5.49...9.5.50)

Updates `ruff` from 0.9.1 to 0.9.2
- [Release notes](https://github.com/astral-sh/ruff/releases)
- [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md)
- [Commits](https://github.com/astral-sh/ruff/compare/0.9.1...0.9.2)

---
updated-dependencies:
- dependency-name: mkdocs-material
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: ruff
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: all
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-20 16:39:34 +13:00
Georg
dd1d148543
Repair systemd reload notifications (#3355)
In order for the RELOAD and the subsequent READY notifications to be
correctly processed, the RELOAD notification must be accompanied with a
MONOTONIC_USEC one.
2025-01-17 15:17:58 +10:00
James Hodgkinson
419c4a1827
fix: unrecoverable error page doesn't include logo or domain name (#3352) 2025-01-14 03:49:20 +00:00
dependabot[bot]
2d439c508f
Bump jinja2 from 3.1.4 to 3.1.5 in /pykanidm in the pip group (#3358)
Bumps the pip group in /pykanidm with 1 update: [jinja2](https://github.com/pallets/jinja).


Updates `jinja2` from 3.1.4 to 3.1.5
- [Release notes](https://github.com/pallets/jinja/releases)
- [Changelog](https://github.com/pallets/jinja/blob/main/CHANGES.rst)
- [Commits](https://github.com/pallets/jinja/compare/3.1.4...3.1.5)

---
updated-dependencies:
- dependency-name: jinja2
  dependency-type: indirect
  dependency-group: pip
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-13 07:46:33 +10:00
dependabot[bot]
ba24ffb1e0
Bump the all group in /pykanidm with 4 updates (#3356)
Bumps the all group in /pykanidm with 4 updates: [pydantic](https://github.com/pydantic/pydantic), [pylint-pydantic](https://github.com/fcfangcc/pylint-pydantic), [pytest-asyncio](https://github.com/pytest-dev/pytest-asyncio) and [ruff](https://github.com/astral-sh/ruff).


Updates `pydantic` from 2.10.4 to 2.10.5
- [Release notes](https://github.com/pydantic/pydantic/releases)
- [Changelog](https://github.com/pydantic/pydantic/blob/main/HISTORY.md)
- [Commits](https://github.com/pydantic/pydantic/compare/v2.10.4...v2.10.5)

Updates `pylint-pydantic` from 0.3.4 to 0.3.5
- [Release notes](https://github.com/fcfangcc/pylint-pydantic/releases)
- [Commits](https://github.com/fcfangcc/pylint-pydantic/compare/v0.3.4...v0.3.5)

Updates `pytest-asyncio` from 0.25.1 to 0.25.2
- [Release notes](https://github.com/pytest-dev/pytest-asyncio/releases)
- [Commits](https://github.com/pytest-dev/pytest-asyncio/compare/v0.25.1...v0.25.2)

Updates `ruff` from 0.8.6 to 0.9.1
- [Release notes](https://github.com/astral-sh/ruff/releases)
- [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md)
- [Commits](https://github.com/astral-sh/ruff/compare/0.8.6...0.9.1)

---
updated-dependencies:
- dependency-name: pydantic
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: pylint-pydantic
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: pytest-asyncio
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: ruff
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: all
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-13 07:15:39 +10:00
Firstyear
e7d91ed55d
20250110 eo fixes (#3353)
While preparing for everything open, I found a small number of doc/book issues, some logging issues, and some minor performance wins. This pr is just small bits of various polish around the place.
2025-01-12 03:53:31 +00:00
Jalil David Salamé Messina
c4bc1ff546
fix(server/config): reduce string allocations (#3350)
Previously the code would do `key.replace("KANIDM_", "")`, this
allocates a new string, which is unnecessary, as we can simply call
`strip_prefix("KANIDM_")`.

This removes the `KANIDM_` prefix from a bunch of places, and doubles as
a check that the variable is prefixed with `KANIDM_`. Overall I believe
this change makes the code more robust and slightly reduces allocations,
speeding up an admittedly cold function (only called very infrequently).
2025-01-10 23:20:15 +00:00
Firstyear
1a29aa7301
Add ssh_publickeys as a claim for oauth2 (#3346)
Allow ssh_publickeys to be exposed as a claim for oauth2 and oidc
applications so that they can consume these keys for various uses.
An example could be something like gitlab which can then associate
the public keys with the users account.
2025-01-08 08:21:28 +00:00
Firstyear
063366cba4
Allow modification of password minimum length (#3345)
Allow all account policy values to be altered on system protected
objects.
2025-01-08 06:51:46 +00:00
micolous
16591007dd
Add OAuth2 response_mode=fragment (#3335)
* Add response_mode=fragment to discovery documents
* Add test for `response_mode=query`
* refactor OAuth 2.0 tests back into regular functions, because macros are messy
* Disallow some `response_type` x `response_mode` combinations per spec
2025-01-08 15:41:01 +10:00
Firstyear
1983ce19e9
Resolve passkey regression (#3343)
During other testing I noticed that passkeys no longer worked
on a reauthentication. This was due to a regression in you
guessed it, cookies, where the auth session id wasn't being
removed properly.
2025-01-07 16:05:14 +10:00
James Hodgkinson
ccf6792104
Renaming "TOTP" in the login flow (#3338) 2025-01-07 00:05:07 +00:00
dependabot[bot]
028bd93059
Bump the all group in /pykanidm with 3 updates (#3339)
Bumps the all group in /pykanidm with 3 updates: [mypy](https://github.com/python/mypy), [pytest-asyncio](https://github.com/pytest-dev/pytest-asyncio) and [ruff](https://github.com/astral-sh/ruff).


Updates `mypy` from 1.14.0 to 1.14.1
- [Changelog](https://github.com/python/mypy/blob/master/CHANGELOG.md)
- [Commits](https://github.com/python/mypy/compare/v1.14.0...v1.14.1)

Updates `pytest-asyncio` from 0.25.0 to 0.25.1
- [Release notes](https://github.com/pytest-dev/pytest-asyncio/releases)
- [Commits](https://github.com/pytest-dev/pytest-asyncio/compare/v0.25.0...v0.25.1)

Updates `ruff` from 0.8.4 to 0.8.6
- [Release notes](https://github.com/astral-sh/ruff/releases)
- [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md)
- [Commits](https://github.com/astral-sh/ruff/compare/0.8.4...0.8.6)

---
updated-dependencies:
- dependency-name: mypy
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: pytest-asyncio
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: ruff
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: all
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-06 14:26:00 +00:00
dependabot[bot]
8ef7d6cb4a
Bump actions/checkout from 2 to 4 in the all group (#3341)
Bumps the all group with 1 update: [actions/checkout](https://github.com/actions/checkout).


Updates `actions/checkout` from 2 to 4
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v2...v4)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: all
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-06 13:35:25 +00:00
George Wu
a3358828a8
Add support for prefers-color-scheme using Bootstrap classes. (#3327)
* Add support for prefers-color-scheme using Bootstrap classes.
* Move stylesheet changes to separate javascript file.
* fix(html): don't specify the integrity hash in the tag for style.js
* fix(log): debug-log integrity hashes for troubleshooting
* fix(css): move to using bootstrap standard variables for colours and theming
* fix(js): rewrite to simplify and use standard bootstrap functionality
* fix(makefile): codespell thingie was complaining
* run prettier on css/js.

---------

Co-authored-by: James Hodgkinson <james@terminaloutcomes.com>
2025-01-06 10:58:42 +00:00
Firstyear
761dda688e
Fix /var/run/kanidm-unixd permission (#3342)
This folder was set to 750 which prevented non-root users from reading the
localhost unixd socket which is required for nss/pam to operate.
2025-01-06 15:58:40 +10:00
James Hodgkinson
b74883ae0d
Javascript linting (#3329)
* feat(ci/dev): adding npm/eslint config for javascript linting
* feat(ci/dev): adding js-prettier config for consistency in formatting
* fix(css): linting
* fix(js): linting the js things
2025-01-04 15:25:46 +10:00
Firstyear
3430a1c31d
Ignore anonymous in oauth2 read allow access (#3336)
Administrators will sometimes configure oauth2 clients with `idm_all_accounts`
as an allowed scope group. Despite anonymous being *unable* to interact with
oauth2, this still allowed oauth2 clients to be read by anonymous in this
configuration. For some users, this may be considered a public info
disclosure.
2025-01-04 03:09:48 +00:00
Firstyear
5562625d75
cookies don't clear unless you set domain (#3332)
* make everything cookie consistent
* Stricter on expiry
* Relearn a painful lesson about needing domains in removal cookies
* fix: DRY cookie creation code and reduce the sins
2025-01-04 00:33:01 +00:00
Firstyear
226274da23
20250102 freebsd client (#3333)
Support freebsd as a unix client
2025-01-04 09:22:44 +10:00
Jinna Kiisuo
5eb9a4430f
fix: PAM on Debian, enable use_first_pass by default (#3326)
Since we use Debian's PAM autoconf, pam_unix isn't disabled and remains active.
This means pam_unix triggers first and pam_kanidm should use the password it already tried to match to a local user.

This change also moves the postinst hook for PAM config correctly to the libpam-kanidm package,
since that's the one that delivers the config that needs a reinstall!
2025-01-01 08:40:14 +10:00
dependabot[bot]
227853f8cd
Bump the all group with 6 updates (#3324)
Bumps the all group with 6 updates:

| Package | From | To |
| --- | --- | --- |
| [quote](https://github.com/dtolnay/quote) | `1.0.37` | `1.0.38` |
| [reqwest](https://github.com/seanmonstar/reqwest) | `0.12.9` | `0.12.11` |
| [serde](https://github.com/serde-rs/serde) | `1.0.216` | `1.0.217` |
| [serde_with](https://github.com/jonasbb/serde_with) | `3.11.0` | `3.12.0` |
| [syn](https://github.com/dtolnay/syn) | `2.0.91` | `2.0.93` |
| [jsonschema](https://github.com/Stranger6667/jsonschema) | `0.26.2` | `0.28.0` |


Updates `quote` from 1.0.37 to 1.0.38
- [Release notes](https://github.com/dtolnay/quote/releases)
- [Commits](https://github.com/dtolnay/quote/compare/1.0.37...1.0.38)

Updates `reqwest` from 0.12.9 to 0.12.11
- [Release notes](https://github.com/seanmonstar/reqwest/releases)
- [Changelog](https://github.com/seanmonstar/reqwest/blob/master/CHANGELOG.md)
- [Commits](https://github.com/seanmonstar/reqwest/compare/v0.12.9...v0.12.11)

Updates `serde` from 1.0.216 to 1.0.217
- [Release notes](https://github.com/serde-rs/serde/releases)
- [Commits](https://github.com/serde-rs/serde/compare/v1.0.216...v1.0.217)

Updates `serde_with` from 3.11.0 to 3.12.0
- [Release notes](https://github.com/jonasbb/serde_with/releases)
- [Commits](https://github.com/jonasbb/serde_with/compare/v3.11.0...v3.12.0)

Updates `syn` from 2.0.91 to 2.0.93
- [Release notes](https://github.com/dtolnay/syn/releases)
- [Commits](https://github.com/dtolnay/syn/compare/2.0.91...2.0.93)

Updates `jsonschema` from 0.26.2 to 0.28.0
- [Release notes](https://github.com/Stranger6667/jsonschema/releases)
- [Changelog](https://github.com/Stranger6667/jsonschema/blob/master/CHANGELOG.md)
- [Commits](https://github.com/Stranger6667/jsonschema/compare/rust-v0.26.2...rust-v0.28.0)

---
updated-dependencies:
- dependency-name: quote
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: reqwest
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: serde
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: serde_with
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: all
- dependency-name: syn
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: jsonschema
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: all
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-29 22:46:26 +00:00
dependabot[bot]
c0e733629f
Bump the all group in /pykanidm with 2 updates (#3323)
Bumps the all group in /pykanidm with 2 updates: [coverage](https://github.com/nedbat/coveragepy) and [mkdocstrings-python](https://github.com/mkdocstrings/python).


Updates `coverage` from 7.6.9 to 7.6.10
- [Release notes](https://github.com/nedbat/coveragepy/releases)
- [Changelog](https://github.com/nedbat/coveragepy/blob/master/CHANGES.rst)
- [Commits](https://github.com/nedbat/coveragepy/compare/7.6.9...7.6.10)

Updates `mkdocstrings-python` from 1.12.2 to 1.13.0
- [Release notes](https://github.com/mkdocstrings/python/releases)
- [Changelog](https://github.com/mkdocstrings/python/blob/main/CHANGELOG.md)
- [Commits](https://github.com/mkdocstrings/python/compare/1.12.2...1.13.0)

---
updated-dependencies:
- dependency-name: coverage
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: mkdocstrings-python
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: all
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-30 08:18:58 +10:00
dependabot[bot]
009200375f
Bump the all group with 3 updates (#3317)
Bumps the all group with 3 updates: [anyhow](https://github.com/dtolnay/anyhow), [serde_json](https://github.com/serde-rs/json) and [syn](https://github.com/dtolnay/syn).


Updates `anyhow` from 1.0.94 to 1.0.95
- [Release notes](https://github.com/dtolnay/anyhow/releases)
- [Commits](https://github.com/dtolnay/anyhow/compare/1.0.94...1.0.95)

Updates `serde_json` from 1.0.133 to 1.0.134
- [Release notes](https://github.com/serde-rs/json/releases)
- [Commits](https://github.com/serde-rs/json/compare/v1.0.133...v1.0.134)

Updates `syn` from 2.0.90 to 2.0.91
- [Release notes](https://github.com/dtolnay/syn/releases)
- [Commits](https://github.com/dtolnay/syn/compare/2.0.90...2.0.91)

---
updated-dependencies:
- dependency-name: anyhow
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: serde_json
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: syn
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-23 00:29:06 +00:00
dependabot[bot]
4113c291ed
Bump the all group in /pykanidm with 7 updates (#3316)
---
updated-dependencies:
- dependency-name: pydantic
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: aiohttp
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: authlib
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: all
- dependency-name: mypy
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: all
- dependency-name: mkdocs-material
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: pook
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: ruff
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: all
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-23 10:02:30 +10:00
Firstyear
c4441c1fca
nss/pam resolver should reauth faster (#3309)
This can have visible impacts on accounts that don't have a pam password
cached yet, but then appear to "stall" for a minute or two until it works
due to the fact that the provider was offline and waiting to reauth.

When we are still connected but our provider auth session has expired
we should reconnect faster. This reduces the timeout for reauthentication
for the provider so that it can return to the online state sooner. We
also loop when we detect the provider session is no longer authenticated
so that we can reauth immediately, rather than causing a noticable
interuption.
2024-12-21 07:08:39 +00:00
Firstyear
bbefb0b1b1
Update to latest webauthn-rs/time (#3315)
This updates to the latest webauthn-rs release. When
updating, an issue with time was found that changes
the behaviour of it's parser for rfc3339. This also
updates our tests to accomodate that change.

Co-authored-by: James Hodgkinson <james@terminaloutcomes.com>
2024-12-21 06:45:06 +00:00
James Hodgkinson
b6f63f3605
kanidm-unixd example config enfixening (#3314)
* kanidm-unixd default config via PPA problem with version 2 on debian bookworm
Fixes #3312

* fix(coverage): moving to using cargo-tarpaulin

* kanidm-unixd default config via PPA problem with version 2 on debian bookworm
Fixes #3312
2024-12-21 15:17:12 +10:00
Firstyear
9f499f3913
Further SCIM sync testing, minor fixes (#3305)
This adds further testing of SCIM sync, especially around
conversion of the SCIM Sync Person and Group types into
SCIM Entry. This test would have prevented #3298 and
 #3299 from occuring.

During testing two more fixes were found. external_id should have
been required (not optional) and a group with no members would
cause a serialisation issue.
2024-12-20 07:16:07 +00:00
Be
c6432cad83
book: explain how to use fido-mds-tool (#3231)
explain how to use fido-mds-tool  to configure Webauthn attestation
2024-12-20 03:18:52 +00:00
Be
2174b9b251
client: read attestation CA list JSON from file (#3232)
instead of passing a giant blob of JSON as a command argument.
Before, it was not possible to allow all valid authenticators
certified by the FIDO Alliance because

fido-mds-list query -o "status gte valid"

outputs a JSON string longer than Linux allows for command
arguments.

Co-authored-by: Firstyear <william@blackhats.net.au>
2024-12-20 03:02:02 +00:00
Firstyear
4f2eb8b5f8
Automatically trigger passkeys on login view (#3307)
Add an on-load handler to pkhtml.js so that when the partial
view is displayed passkey auth is automatically prompted for.
If the users browser blocks this event, the fallback manual
buttons still exist.
2024-12-19 05:46:15 +00:00
William Brown
c59f560e50 Re-add enrol another device flow
This was a commonly requested re-addition to the new webui. This
adds the ability for someone to scan a qr code or follow a link
to enrol another device to their account.
2024-12-19 13:48:59 +10:00
William Brown
11438a9dd5 Improved Cookie Removal
If a path isn't set then cookies aren't removed. More aggressively
remove cookies when they are no longer required.
2024-12-19 13:48:59 +10:00
Firstyear
50a7d9d700
Allow opt-in of easter eggs (#3308)
So that we can start to add some more easter eggs to the server,
we also need to respect user preferences that may not want them.

This adds a configuration setting to the domain allowing a release
build to opt-in to easter eggs, and development builds to opt-out
of them.
2024-12-19 03:30:35 +00:00
Firstyear
1fbbf323fa
Allow reseting account policy values to defaults (#3306)
* Allow reseting account policy values to defaults

This allows the admin cli to reset account policy values to
defaults by clearing them. Due to how account policy resolves
a lack of value implies the default.
2024-12-18 17:43:56 +10:00
Firstyear
44e7348f3b
Incorrect member name in groups (#3302)
Member was accidentally set to members which prevented
group synchronisation.
2024-12-17 06:57:26 +00:00
Firstyear
0b2f349aec
SCIM Sync Missing Annotation (#3300)
A missing serde annotion in SCIM Sync caused groups to fail to
sync unless they had a description. This resolves the failure
by adding the correct annotation to skip None fields in groups.
2024-12-17 14:18:30 +10:00
Firstyear
eba8dff23a
Ignore system users for UPG synthesiseation (#3297)
Our unix resolver would attempt the right thing to synthesise
user private groups on linux as these are an important security
boundary. However, it turns out that almost every distro has
botched their default system user accounts, and many are
installed with numeric-only UPGs that don't resolve. In the
case that later the user does attempt to fix that, because we
synthesised as UPG for the system account, the user trying to
add the UPG would now fail. In some cases this could cause
system updates to be prevented from installing.

This change limits UPG synth to user accounts only (uid > 1000)
which is the common uid boundary on unix-like platforms.
2024-12-17 13:08:17 +10:00
Firstyear
7e9c33ab03
Limit OAuth2 resumption to session (#3296)
OAuth2 session resumption was accidentally made a permanent cookie
which led to continuing issues with it causing invalid redirections
after login. Make this a session only cookie.
2024-12-17 11:37:16 +10:00
Firstyear
6c3b8500a2
Use specific errors for intent token revoked (#3291)
Rather than the generic 'invalid state' error, we now return
proper site-specific errors for credential commit failures, with
error messages to explain what went wrong.
2024-12-16 10:28:00 +10:00
Firstyear
5d75c9b247
Autocomplete password during reauth with TOTP (#3290)
During a re-auth flow, the password was not autocompleted once
totp was autocompleted. This is because in a normal login flow
the autocomplete is performed on the first login.html page,
but in a re-auth we skip that page.

This adds the proper handling to allow the pw to autofill
in the background once the TOTP is completed.
2024-12-15 23:43:29 +00:00
dependabot[bot]
6db0cdc345
Bump the all group with 6 updates (#3294)
Bumps the all group with 6 updates:

| Package | From | To |
| --- | --- | --- |
| [chrono](https://github.com/chronotope/chrono) | `0.4.38` | `0.4.39` |
| [libc](https://github.com/rust-lang/libc) | `0.2.167` | `0.2.168` |
| [rustls](https://github.com/rustls/rustls) | `0.23.19` | `0.23.20` |
| [serde](https://github.com/serde-rs/serde) | `1.0.215` | `1.0.216` |
| [tower](https://github.com/tower-rs/tower) | `0.5.1` | `0.5.2` |
| [fantoccini](https://github.com/jonhoo/fantoccini) | `0.21.2` | `0.21.3` |


Updates `chrono` from 0.4.38 to 0.4.39
- [Release notes](https://github.com/chronotope/chrono/releases)
- [Changelog](https://github.com/chronotope/chrono/blob/main/CHANGELOG.md)
- [Commits](https://github.com/chronotope/chrono/compare/v0.4.38...v0.4.39)

Updates `libc` from 0.2.167 to 0.2.168
- [Release notes](https://github.com/rust-lang/libc/releases)
- [Changelog](https://github.com/rust-lang/libc/blob/0.2.168/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/libc/compare/0.2.167...0.2.168)

Updates `rustls` from 0.23.19 to 0.23.20
- [Release notes](https://github.com/rustls/rustls/releases)
- [Changelog](https://github.com/rustls/rustls/blob/main/CHANGELOG.md)
- [Commits](https://github.com/rustls/rustls/compare/v/0.23.19...v/0.23.20)

Updates `serde` from 1.0.215 to 1.0.216
- [Release notes](https://github.com/serde-rs/serde/releases)
- [Commits](https://github.com/serde-rs/serde/compare/v1.0.215...v1.0.216)

Updates `tower` from 0.5.1 to 0.5.2
- [Release notes](https://github.com/tower-rs/tower/releases)
- [Commits](https://github.com/tower-rs/tower/compare/tower-0.5.1...tower-0.5.2)

Updates `fantoccini` from 0.21.2 to 0.21.3
- [Commits](https://github.com/jonhoo/fantoccini/compare/v0.21.2...v0.21.3)

---
updated-dependencies:
- dependency-name: chrono
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: libc
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: rustls
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: serde
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: tower
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: fantoccini
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-15 22:17:05 +00:00
dependabot[bot]
6abdb12e35
Bump mozilla-actions/sccache-action from 0.0.6 to 0.0.7 in the all group (#3295)
Bumps the all group with 1 update: [mozilla-actions/sccache-action](https://github.com/mozilla-actions/sccache-action).


Updates `mozilla-actions/sccache-action` from 0.0.6 to 0.0.7
- [Release notes](https://github.com/mozilla-actions/sccache-action/releases)
- [Commits](https://github.com/mozilla-actions/sccache-action/compare/v0.0.6...v0.0.7)

---
updated-dependencies:
- dependency-name: mozilla-actions/sccache-action
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-16 07:50:01 +10:00
dependabot[bot]
d62c17cd0e
Bump the all group in /pykanidm with 2 updates (#3293)
Bumps the all group in /pykanidm with 2 updates: [pytest-asyncio](https://github.com/pytest-dev/pytest-asyncio) and [ruff](https://github.com/astral-sh/ruff).


Updates `pytest-asyncio` from 0.24.0 to 0.25.0
- [Release notes](https://github.com/pytest-dev/pytest-asyncio/releases)
- [Commits](https://github.com/pytest-dev/pytest-asyncio/compare/v0.24.0...v0.25.0)

Updates `ruff` from 0.8.2 to 0.8.3
- [Release notes](https://github.com/astral-sh/ruff/releases)
- [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md)
- [Commits](https://github.com/astral-sh/ruff/compare/0.8.2...0.8.3)

---
updated-dependencies:
- dependency-name: pytest-asyncio
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: all
- dependency-name: ruff
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: all
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-15 20:27:40 +00:00
Firstyear
a8d149db16
remove unused webauthn features. (#3286)
While improving the webauthn feature handling yesterday I accidentally left mozilla enabled on linux which doesn't need it and u2fhid on macos.

In the future the plan is to swap fully to u2fhid, but in the mean time we need mozilla for freebsd support. That's something I'll need to work on later with @micolous.
2024-12-12 22:19:10 -05:00
Firstyear
5dfba2a0ef
Add CORS headers to jwks and userinfo (#3283)
When using jwks from a single page application, the keys and
userinfo were unable to be retrieved due to missing cors headers.
2024-12-13 00:23:54 +00:00
Firstyear
60cc830ebd
Cleanup webauthn features (#3285) 2024-12-12 06:56:12 -05:00
Firstyear
4ee9a3a098
Minor tweaks to cred reset ui (#3284) 2024-12-11 21:53:22 +00:00
dependabot[bot]
b2906829e2
Bump the all group across 1 directory with 6 updates (#3280)
Bumps the all group with 6 updates in the /pykanidm directory:

| Package | From | To |
| --- | --- | --- |
| [pydantic](https://github.com/pydantic/pydantic) | `2.10.2` | `2.10.3` |
| [aiohttp](https://github.com/aio-libs/aiohttp) | `3.11.8` | `3.11.10` |
| [pylint-pydantic](https://github.com/fcfangcc/pylint-pydantic) | `0.3.2` | `0.3.4` |
| [coverage](https://github.com/nedbat/coveragepy) | `7.6.8` | `7.6.9` |
| [mkdocs-material](https://github.com/squidfunk/mkdocs-material) | `9.5.47` | `9.5.48` |
| [ruff](https://github.com/astral-sh/ruff) | `0.8.1` | `0.8.2` |



Updates `pydantic` from 2.10.2 to 2.10.3
- [Release notes](https://github.com/pydantic/pydantic/releases)
- [Changelog](https://github.com/pydantic/pydantic/blob/main/HISTORY.md)
- [Commits](https://github.com/pydantic/pydantic/compare/v2.10.2...v2.10.3)

Updates `aiohttp` from 3.11.8 to 3.11.10
- [Release notes](https://github.com/aio-libs/aiohttp/releases)
- [Changelog](https://github.com/aio-libs/aiohttp/blob/master/CHANGES.rst)
- [Commits](https://github.com/aio-libs/aiohttp/compare/v3.11.8...v3.11.10)

Updates `pylint-pydantic` from 0.3.2 to 0.3.4
- [Release notes](https://github.com/fcfangcc/pylint-pydantic/releases)
- [Commits](https://github.com/fcfangcc/pylint-pydantic/compare/v0.3.2...v0.3.4)

Updates `coverage` from 7.6.8 to 7.6.9
- [Release notes](https://github.com/nedbat/coveragepy/releases)
- [Changelog](https://github.com/nedbat/coveragepy/blob/master/CHANGES.rst)
- [Commits](https://github.com/nedbat/coveragepy/compare/7.6.8...7.6.9)

Updates `mkdocs-material` from 9.5.47 to 9.5.48
- [Release notes](https://github.com/squidfunk/mkdocs-material/releases)
- [Changelog](https://github.com/squidfunk/mkdocs-material/blob/master/CHANGELOG)
- [Commits](https://github.com/squidfunk/mkdocs-material/compare/9.5.47...9.5.48)

Updates `ruff` from 0.8.1 to 0.8.2
- [Release notes](https://github.com/astral-sh/ruff/releases)
- [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md)
- [Commits](https://github.com/astral-sh/ruff/compare/0.8.1...0.8.2)

---
updated-dependencies:
- dependency-name: pydantic
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: aiohttp
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: pylint-pydantic
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: coverage
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: mkdocs-material
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: ruff
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: all
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-11 14:49:46 +00:00
Firstyear
07b9ca8939
Allow group managers to modify entry-managed-by (#3272)
When we added entry-managed-by, we allowed it to be set on group creation but not post-group-creation. The idea was to delegate ownership of the group. However, this has the obvious trap that an account group like idm_admins can't alter entry-managed-by post creation, needing the use of the admin account which has access control privs, or a delete and recreate of the entry.

Since the idm admin could delete and recreate the group with a new entry manager, there is functionally no difference to allowing them to modify the entry-managed-by here of low priv groups. This changes the group manager access control by default to allow this.
2024-12-10 03:49:57 +00:00
George Wu
cae780e091
pykanidm: Make a little dry. (#3281)
* pykanidm: Make a little dry
2024-12-09 04:50:20 +00:00
dependabot[bot]
5dfbf7ca79
Bump the all group with 5 updates (#3278)
Bumps the all group with 5 updates:

| Package | From | To |
| --- | --- | --- |
| [anyhow](https://github.com/dtolnay/anyhow) | `1.0.93` | `1.0.94` |
| [clap](https://github.com/clap-rs/clap) | `4.5.21` | `4.5.23` |
| [http](https://github.com/hyperium/http) | `1.1.0` | `1.2.0` |
| [tokio](https://github.com/tokio-rs/tokio) | `1.41.1` | `1.42.0` |
| [tokio-util](https://github.com/tokio-rs/tokio) | `0.7.12` | `0.7.13` |


Updates `anyhow` from 1.0.93 to 1.0.94
- [Release notes](https://github.com/dtolnay/anyhow/releases)
- [Commits](https://github.com/dtolnay/anyhow/compare/1.0.93...1.0.94)

Updates `clap` from 4.5.21 to 4.5.23
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/clap_complete-v4.5.21...clap_complete-v4.5.23)

Updates `http` from 1.1.0 to 1.2.0
- [Release notes](https://github.com/hyperium/http/releases)
- [Changelog](https://github.com/hyperium/http/blob/master/CHANGELOG.md)
- [Commits](https://github.com/hyperium/http/compare/v1.1.0...v1.2.0)

Updates `tokio` from 1.41.1 to 1.42.0
- [Release notes](https://github.com/tokio-rs/tokio/releases)
- [Commits](https://github.com/tokio-rs/tokio/compare/tokio-1.41.1...tokio-1.42.0)

Updates `tokio-util` from 0.7.12 to 0.7.13
- [Release notes](https://github.com/tokio-rs/tokio/releases)
- [Commits](https://github.com/tokio-rs/tokio/compare/tokio-util-0.7.12...tokio-util-0.7.13)

---
updated-dependencies:
- dependency-name: anyhow
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: clap
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: http
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: all
- dependency-name: tokio
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: all
- dependency-name: tokio-util
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-09 03:44:41 +00:00
George Wu
97a1c39d62
pykanidm: Add retrieving credential reset token for a person. (#3279) 2024-12-08 21:52:51 -05:00
Firstyear
9b3350f753
Cleanup of println and other outputs (#3266) 2024-12-04 15:13:14 +10:00
James Hodgkinson
516874460b
Canonicalize path for user shell check (#3265) 2024-12-04 11:55:30 +10:00
James Hodgkinson
388ed679a8
Check DNS on replication loop start not at task start (#3243) 2024-12-03 03:58:16 +00:00
Firstyear
64fcb61d5e
Work around systemd race condition (#3262)
Systemd reload can't handle us reloading so quickly which
causes "reload or restart" to always "restart" kanidm incorrectly.
2024-12-03 03:09:05 +00:00
James Hodgkinson
42459f56b0
fix(docstrings): minor lack of formatting breaking things (#3260) 2024-12-03 12:52:31 +10:00
James Hodgkinson
4f53bce3d3
Devcontainertainertainer (#3251) 2024-12-02 11:02:56 +00:00
Peter Lehmann
ac3cf1f363
grafana: update example to work with strict redirect uri checking (#3259) 2024-12-02 05:40:01 +00:00
dependabot[bot]
b4ca356b8d
Bump the all group in /pykanidm with 5 updates (#3257)
Bumps the all group in /pykanidm with 5 updates:

| Package | From | To |
| --- | --- | --- |
| [pydantic](https://github.com/pydantic/pydantic) | `2.10.1` | `2.10.2` |
| [aiohttp](https://github.com/aio-libs/aiohttp) | `3.11.7` | `3.11.8` |
| [pytest](https://github.com/pytest-dev/pytest) | `8.3.3` | `8.3.4` |
| [mkdocs-material](https://github.com/squidfunk/mkdocs-material) | `9.5.45` | `9.5.47` |
| [ruff](https://github.com/astral-sh/ruff) | `0.8.0` | `0.8.1` |


Updates `pydantic` from 2.10.1 to 2.10.2
- [Release notes](https://github.com/pydantic/pydantic/releases)
- [Changelog](https://github.com/pydantic/pydantic/blob/main/HISTORY.md)
- [Commits](https://github.com/pydantic/pydantic/compare/v2.10.1...v2.10.2)

Updates `aiohttp` from 3.11.7 to 3.11.8
- [Release notes](https://github.com/aio-libs/aiohttp/releases)
- [Changelog](https://github.com/aio-libs/aiohttp/blob/master/CHANGES.rst)
- [Commits](https://github.com/aio-libs/aiohttp/compare/v3.11.7...v3.11.8)

Updates `pytest` from 8.3.3 to 8.3.4
- [Release notes](https://github.com/pytest-dev/pytest/releases)
- [Changelog](https://github.com/pytest-dev/pytest/blob/main/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest/compare/8.3.3...8.3.4)

Updates `mkdocs-material` from 9.5.45 to 9.5.47
- [Release notes](https://github.com/squidfunk/mkdocs-material/releases)
- [Changelog](https://github.com/squidfunk/mkdocs-material/blob/master/CHANGELOG)
- [Commits](https://github.com/squidfunk/mkdocs-material/compare/9.5.45...9.5.47)

Updates `ruff` from 0.8.0 to 0.8.1
- [Release notes](https://github.com/astral-sh/ruff/releases)
- [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md)
- [Commits](https://github.com/astral-sh/ruff/compare/0.8.0...0.8.1)

---
updated-dependencies:
- dependency-name: pydantic
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: aiohttp
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: pytest
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: mkdocs-material
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: ruff
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: all
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-01 22:20:14 +00:00
dependabot[bot]
a9c354d578
Bump the all group with 6 updates (#3258)
Bumps the all group with 6 updates:

| Package | From | To |
| --- | --- | --- |
| [bytes](https://github.com/tokio-rs/bytes) | `1.8.0` | `1.9.0` |
| [libc](https://github.com/rust-lang/libc) | `0.2.164` | `0.2.167` |
| [rustls](https://github.com/rustls/rustls) | `0.23.18` | `0.23.19` |
| [syn](https://github.com/dtolnay/syn) | `2.0.89` | `2.0.90` |
| [tracing](https://github.com/tokio-rs/tracing) | `0.1.40` | `0.1.41` |
| [tracing-subscriber](https://github.com/tokio-rs/tracing) | `0.3.18` | `0.3.19` |


Updates `bytes` from 1.8.0 to 1.9.0
- [Release notes](https://github.com/tokio-rs/bytes/releases)
- [Changelog](https://github.com/tokio-rs/bytes/blob/master/CHANGELOG.md)
- [Commits](https://github.com/tokio-rs/bytes/compare/v1.8.0...v1.9.0)

Updates `libc` from 0.2.164 to 0.2.167
- [Release notes](https://github.com/rust-lang/libc/releases)
- [Changelog](https://github.com/rust-lang/libc/blob/0.2.167/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/libc/compare/0.2.164...0.2.167)

Updates `rustls` from 0.23.18 to 0.23.19
- [Release notes](https://github.com/rustls/rustls/releases)
- [Changelog](https://github.com/rustls/rustls/blob/main/CHANGELOG.md)
- [Commits](https://github.com/rustls/rustls/compare/v/0.23.18...v/0.23.19)

Updates `syn` from 2.0.89 to 2.0.90
- [Release notes](https://github.com/dtolnay/syn/releases)
- [Commits](https://github.com/dtolnay/syn/compare/2.0.89...2.0.90)

Updates `tracing` from 0.1.40 to 0.1.41
- [Release notes](https://github.com/tokio-rs/tracing/releases)
- [Commits](https://github.com/tokio-rs/tracing/compare/tracing-0.1.40...tracing-0.1.41)

Updates `tracing-subscriber` from 0.3.18 to 0.3.19
- [Release notes](https://github.com/tokio-rs/tracing/releases)
- [Commits](https://github.com/tokio-rs/tracing/compare/tracing-subscriber-0.3.18...tracing-subscriber-0.3.19)

---
updated-dependencies:
- dependency-name: bytes
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: all
- dependency-name: libc
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: rustls
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: syn
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: tracing
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: tracing-subscriber
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-02 07:56:02 +10:00
Firstyear
ea0e63cc2a
20240927 SCIM put (#3151) 2024-11-30 06:56:17 +00:00
Firstyear
8bbdf6bd6a
Clear invalid tokens from unix resolver (#3256) 2024-11-30 06:32:10 +00:00
Firstyear
db101e6d26
Clippy Lints (#3255) 2024-11-30 06:13:26 +00:00
James Hodgkinson
c1ed939c28
Allow OAuth2 loopback redirects if the path matches (#3252) 2024-11-30 05:40:05 +00:00
Firstyear
4528a1bda0
Correctly display domain name on login (#3254) 2024-11-30 04:13:27 +00:00
Firstyear
52987ab8b2
Display account_id during success/deny paths in unixd (#3253) 2024-11-30 13:57:01 +10:00
George Wu
974fec1d93
s/idm_people_self_write_mail/idm_people_self_mail_write/g (#3250) 2024-11-30 09:13:34 +10:00
James Hodgkinson
a5adf8bcad
handle missing map_group setting in config (#3242) 2024-11-29 02:03:48 +00:00
micolous
fa77076a95
owncloud: Add SameSite=Lax config for cross-domain auth (#3245) 2024-11-28 17:44:12 +10:00
dependabot[bot]
615f07f7d3
Bump the all group across 1 directory with 7 updates (#3238)
* Bump the all group across 1 directory with 7 updates

Bumps the all group with 7 updates in the /pykanidm directory:

| Package | From | To |
| --- | --- | --- |
| [pydantic](https://github.com/pydantic/pydantic) | `2.9.2` | `2.10.1` |
| [aiohttp](https://github.com/aio-libs/aiohttp) | `3.10.11` | `3.11.7` |
| [coverage](https://github.com/nedbat/coveragepy) | `7.6.4` | `7.6.8` |
| [mkdocs-material](https://github.com/squidfunk/mkdocs-material) | `9.5.44` | `9.5.45` |
| [mkdocstrings](https://github.com/mkdocstrings/mkdocstrings) | `0.26.2` | `0.27.0` |
| [pook](https://github.com/h2non/pook) | `2.1.1` | `2.1.2` |
| [ruff](https://github.com/astral-sh/ruff) | `0.7.2` | `0.8.0` |



Updates `pydantic` from 2.9.2 to 2.10.1
- [Release notes](https://github.com/pydantic/pydantic/releases)
- [Changelog](https://github.com/pydantic/pydantic/blob/main/HISTORY.md)
- [Commits](https://github.com/pydantic/pydantic/compare/v2.9.2...v2.10.1)

Updates `aiohttp` from 3.10.11 to 3.11.7
- [Release notes](https://github.com/aio-libs/aiohttp/releases)
- [Changelog](https://github.com/aio-libs/aiohttp/blob/master/CHANGES.rst)
- [Commits](https://github.com/aio-libs/aiohttp/compare/v3.10.11...v3.11.7)

Updates `coverage` from 7.6.4 to 7.6.8
- [Release notes](https://github.com/nedbat/coveragepy/releases)
- [Changelog](https://github.com/nedbat/coveragepy/blob/master/CHANGES.rst)
- [Commits](https://github.com/nedbat/coveragepy/compare/7.6.4...7.6.8)

Updates `mkdocs-material` from 9.5.44 to 9.5.45
- [Release notes](https://github.com/squidfunk/mkdocs-material/releases)
- [Changelog](https://github.com/squidfunk/mkdocs-material/blob/master/CHANGELOG)
- [Commits](https://github.com/squidfunk/mkdocs-material/compare/9.5.44...9.5.45)

Updates `mkdocstrings` from 0.26.2 to 0.27.0
- [Release notes](https://github.com/mkdocstrings/mkdocstrings/releases)
- [Changelog](https://github.com/mkdocstrings/mkdocstrings/blob/main/CHANGELOG.md)
- [Commits](https://github.com/mkdocstrings/mkdocstrings/compare/0.26.2...0.27.0)

Updates `pook` from 2.1.1 to 2.1.2
- [Release notes](https://github.com/h2non/pook/releases)
- [Changelog](https://github.com/h2non/pook/blob/master/History.rst)
- [Commits](https://github.com/h2non/pook/compare/v2.1.1...v2.1.2)

Updates `ruff` from 0.7.2 to 0.8.0
- [Release notes](https://github.com/astral-sh/ruff/releases)
- [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md)
- [Commits](https://github.com/astral-sh/ruff/compare/0.7.2...0.8.0)

---
updated-dependencies:
- dependency-name: pydantic
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: all
- dependency-name: aiohttp
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: all
- dependency-name: coverage
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: mkdocs-material
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: mkdocstrings
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: all
- dependency-name: pook
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: ruff
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: all
...

Signed-off-by: dependabot[bot] <support@github.com>

* fixing minor mypy issue

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: James Hodgkinson <james@terminaloutcomes.com>
2024-11-25 20:33:18 +10:00
James Hodgkinson
0054fe17fe
Yaleman/issue3229 (#3239)
* Fix wrong success message on kanidm group set-entry-manager #3229
2024-11-25 09:38:46 +10:00
dependabot[bot]
767c5014d5
Bump the all group across 1 directory with 12 updates (#3235)
Bumps the all group with 12 updates in the / directory:

| Package | From | To |
| --- | --- | --- |
| [axum](https://github.com/tokio-rs/axum) | `0.7.7` | `0.7.9` |
| [clap](https://github.com/clap-rs/clap) | `4.5.20` | `4.5.21` |
| [clap_complete](https://github.com/clap-rs/clap) | `4.5.37` | `4.5.38` |
| [hyper](https://github.com/hyperium/hyper) | `1.5.0` | `1.5.1` |
| [libc](https://github.com/rust-lang/libc) | `0.2.162` | `0.2.164` |
| [proc-macro2](https://github.com/dtolnay/proc-macro2) | `1.0.89` | `1.0.92` |
| [rustls](https://github.com/rustls/rustls) | `0.23.16` | `0.23.18` |
| [serde](https://github.com/serde-rs/serde) | `1.0.214` | `1.0.215` |
| [serde_json](https://github.com/serde-rs/json) | `1.0.132` | `1.0.133` |
| [syn](https://github.com/dtolnay/syn) | `2.0.87` | `2.0.89` |
| [axum-extra](https://github.com/tokio-rs/axum) | `0.9.4` | `0.9.6` |
| [tower-http](https://github.com/tower-rs/tower-http) | `0.6.1` | `0.6.2` |



Updates `axum` from 0.7.7 to 0.7.9
- [Release notes](https://github.com/tokio-rs/axum/releases)
- [Changelog](https://github.com/tokio-rs/axum/blob/main/CHANGELOG.md)
- [Commits](https://github.com/tokio-rs/axum/compare/axum-v0.7.7...axum-v0.7.9)

Updates `clap` from 4.5.20 to 4.5.21
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/clap_complete-v4.5.20...clap_complete-v4.5.21)

Updates `clap_complete` from 4.5.37 to 4.5.38
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/clap_complete-v4.5.37...clap_complete-v4.5.38)

Updates `hyper` from 1.5.0 to 1.5.1
- [Release notes](https://github.com/hyperium/hyper/releases)
- [Changelog](https://github.com/hyperium/hyper/blob/master/CHANGELOG.md)
- [Commits](https://github.com/hyperium/hyper/compare/v1.5.0...v1.5.1)

Updates `libc` from 0.2.162 to 0.2.164
- [Release notes](https://github.com/rust-lang/libc/releases)
- [Changelog](https://github.com/rust-lang/libc/blob/main/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/libc/compare/0.2.162...0.2.164)

Updates `proc-macro2` from 1.0.89 to 1.0.92
- [Release notes](https://github.com/dtolnay/proc-macro2/releases)
- [Commits](https://github.com/dtolnay/proc-macro2/compare/1.0.89...1.0.92)

Updates `rustls` from 0.23.16 to 0.23.18
- [Release notes](https://github.com/rustls/rustls/releases)
- [Changelog](https://github.com/rustls/rustls/blob/main/CHANGELOG.md)
- [Commits](https://github.com/rustls/rustls/compare/v/0.23.16...v/0.23.18)

Updates `serde` from 1.0.214 to 1.0.215
- [Release notes](https://github.com/serde-rs/serde/releases)
- [Commits](https://github.com/serde-rs/serde/compare/v1.0.214...v1.0.215)

Updates `serde_json` from 1.0.132 to 1.0.133
- [Release notes](https://github.com/serde-rs/json/releases)
- [Commits](https://github.com/serde-rs/json/compare/v1.0.132...v1.0.133)

Updates `syn` from 2.0.87 to 2.0.89
- [Release notes](https://github.com/dtolnay/syn/releases)
- [Commits](https://github.com/dtolnay/syn/compare/2.0.87...2.0.89)

Updates `axum-extra` from 0.9.4 to 0.9.6
- [Release notes](https://github.com/tokio-rs/axum/releases)
- [Changelog](https://github.com/tokio-rs/axum/blob/main/CHANGELOG.md)
- [Commits](https://github.com/tokio-rs/axum/compare/axum-extra-v0.9.4...axum-extra-v0.9.6)

Updates `tower-http` from 0.6.1 to 0.6.2
- [Release notes](https://github.com/tower-rs/tower-http/releases)
- [Commits](https://github.com/tower-rs/tower-http/compare/tower-http-0.6.1...tower-http-0.6.2)

---
updated-dependencies:
- dependency-name: axum
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: clap
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: clap_complete
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: hyper
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: libc
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: proc-macro2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: rustls
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: serde
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: serde_json
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: syn
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: axum-extra
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: tower-http
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-24 23:18:24 +10:00
Firstyear
bd53c88229
Update to latest fido-mds-tool (#3230) 2024-11-22 06:57:39 +00:00
Firstyear
d2f5e13c97
Warn when v2 options are used in v1 unixd config (#3228)
Options like map_group would fail silently when version=2 wasn't
set in our unix config. this detects that case and warns that it
is occuring.

To prevent this in the future, we deny unknown keys in v2 so that
if (when?) we add v3, new keys will cause an error.
2024-11-22 02:02:04 +00:00
dependabot[bot]
5393891ea8
Bump aiohttp from 3.10.10 to 3.10.11 in /pykanidm in the pip group (#3223)
Bumps the pip group in /pykanidm with 1 update: [aiohttp](https://github.com/aio-libs/aiohttp).


Updates `aiohttp` from 3.10.10 to 3.10.11
- [Release notes](https://github.com/aio-libs/aiohttp/releases)
- [Changelog](https://github.com/aio-libs/aiohttp/blob/master/CHANGES.rst)
- [Commits](https://github.com/aio-libs/aiohttp/compare/v3.10.10...v3.10.11)

---
updated-dependencies:
- dependency-name: aiohttp
  dependency-type: direct:production
  dependency-group: pip
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-21 10:27:43 +00:00
Firstyear
809cacdb85
Resolve UI Auth Loop with OAuth2 (#3226)
If an OAuth2 auth request resume cookie was present, and at the same
time the kani instance was restarted, the cookie would now fail
to validate on the instance. This caused the user to experience an auth
loop where after every authentication they would see an error *despite*
logging in correctly, and then a refresh would show the correct
apps page.

This removes the auth_req cookie correctly even if it fails to
deserialise.
2024-11-21 09:29:35 +00:00
Firstyear
ce0ad8f854
Harden transport in pam unixd (#3227)
In some cases if the transport drops out from underneath unixd,
it can be difficult to diagnose and leads to inconsistent errors
and output such as prompting for a password multiple times when
it can't succeed.

This makes it clearer that the transport had an error, and it
denies the inflight authsession to prevent spurious password
prompts.
2024-11-21 07:43:14 +00:00
Firstyear
7348c0348a
Improve warning around invalid JWT deserialisation (#3224)
* Improve warning around invalid JWT deserialisation

* typo
2024-11-21 06:52:43 +00:00
George Wu
505e7d9530
Update and fix server config files in examples. (#3225) 2024-11-20 16:57:49 +10:00
George Wu
ed38e92448
Change CLI oauth2 command from set-display-name to set-displayname for consistency. (#3212)
* Change CLI domain command from set-display-name to set-displayname for consistency.

* Also fix CLI.
2024-11-19 04:28:07 +00:00
George Wu
155225c0f9
Add docs on customising Kanidm. (#3209)
* Add docs on customising Kanidm.

* Add more info about images that can be used.

* s/set-display-name/set-displayname/g
2024-11-19 01:37:44 +00:00
Georg
77e13b817a
Correct spelling of occurred (#3222)
Signed-off-by: Georg Pfuetzenreuter <mail@georg-pfuetzenreuter.net>
2024-11-19 00:37:51 +00:00
dependabot[bot]
9c49c831c1
Bump the all group across 1 directory with 13 updates (#3202)
Bumps the all group with 13 updates in the / directory:

| Package | From | To |
| --- | --- | --- |
| [anyhow](https://github.com/dtolnay/anyhow) | `1.0.91` | `1.0.93` |
| [clap_complete](https://github.com/clap-rs/clap) | `4.5.35` | `4.5.37` |
| [csv](https://github.com/BurntSushi/rust-csv) | `1.3.0` | `1.3.1` |
| [hyper-util](https://github.com/hyperium/hyper-util) | `0.1.9` | `0.1.10` |
| [libc](https://github.com/rust-lang/libc) | `0.2.161` | `0.2.162` |
| [reqwest](https://github.com/seanmonstar/reqwest) | `0.12.8` | `0.12.9` |
| [rustls](https://github.com/rustls/rustls) | `0.23.15` | `0.23.16` |
| [serde](https://github.com/serde-rs/serde) | `1.0.213` | `1.0.214` |
| [syn](https://github.com/dtolnay/syn) | `2.0.85` | `2.0.87` |
| [tempfile](https://github.com/Stebalien/tempfile) | `3.13.0` | `3.14.0` |
| [tokio](https://github.com/tokio-rs/tokio) | `1.41.0` | `1.41.1` |
| [escargot](https://github.com/crate-ci/escargot) | `0.5.12` | `0.5.13` |
| [jsonschema](https://github.com/Stranger6667/jsonschema) | `0.26.0` | `0.26.1` |



Updates `anyhow` from 1.0.91 to 1.0.93
- [Release notes](https://github.com/dtolnay/anyhow/releases)
- [Commits](https://github.com/dtolnay/anyhow/compare/1.0.91...1.0.93)

Updates `clap_complete` from 4.5.35 to 4.5.37
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/clap_complete-v4.5.35...clap_complete-v4.5.37)

Updates `csv` from 1.3.0 to 1.3.1
- [Commits](https://github.com/BurntSushi/rust-csv/compare/1.3.0...1.3.1)

Updates `hyper-util` from 0.1.9 to 0.1.10
- [Release notes](https://github.com/hyperium/hyper-util/releases)
- [Changelog](https://github.com/hyperium/hyper-util/blob/master/CHANGELOG.md)
- [Commits](https://github.com/hyperium/hyper-util/compare/v0.1.9...v0.1.10)

Updates `libc` from 0.2.161 to 0.2.162
- [Release notes](https://github.com/rust-lang/libc/releases)
- [Changelog](https://github.com/rust-lang/libc/blob/0.2.162/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/libc/compare/0.2.161...0.2.162)

Updates `reqwest` from 0.12.8 to 0.12.9
- [Release notes](https://github.com/seanmonstar/reqwest/releases)
- [Changelog](https://github.com/seanmonstar/reqwest/blob/master/CHANGELOG.md)
- [Commits](https://github.com/seanmonstar/reqwest/compare/v0.12.8...v0.12.9)

Updates `rustls` from 0.23.15 to 0.23.16
- [Release notes](https://github.com/rustls/rustls/releases)
- [Changelog](https://github.com/rustls/rustls/blob/main/CHANGELOG.md)
- [Commits](https://github.com/rustls/rustls/compare/v/0.23.15...v/0.23.16)

Updates `serde` from 1.0.213 to 1.0.214
- [Release notes](https://github.com/serde-rs/serde/releases)
- [Commits](https://github.com/serde-rs/serde/compare/v1.0.213...v1.0.214)

Updates `syn` from 2.0.85 to 2.0.87
- [Release notes](https://github.com/dtolnay/syn/releases)
- [Commits](https://github.com/dtolnay/syn/compare/2.0.85...2.0.87)

Updates `tempfile` from 3.13.0 to 3.14.0
- [Changelog](https://github.com/Stebalien/tempfile/blob/master/CHANGELOG.md)
- [Commits](https://github.com/Stebalien/tempfile/compare/v3.13.0...v3.14.0)

Updates `tokio` from 1.41.0 to 1.41.1
- [Release notes](https://github.com/tokio-rs/tokio/releases)
- [Commits](https://github.com/tokio-rs/tokio/compare/tokio-1.41.0...tokio-1.41.1)

Updates `escargot` from 0.5.12 to 0.5.13
- [Changelog](https://github.com/crate-ci/escargot/blob/master/CHANGELOG.md)
- [Commits](https://github.com/crate-ci/escargot/compare/v0.5.12...v0.5.13)

Updates `jsonschema` from 0.26.0 to 0.26.1
- [Release notes](https://github.com/Stranger6667/jsonschema/releases)
- [Changelog](https://github.com/Stranger6667/jsonschema/blob/master/CHANGELOG.md)
- [Commits](https://github.com/Stranger6667/jsonschema/compare/rust-v0.26.0...rust-v0.26.1)

---
updated-dependencies:
- dependency-name: anyhow
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: clap_complete
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: csv
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: hyper-util
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: libc
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: reqwest
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: rustls
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: serde
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: syn
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: tempfile
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: all
- dependency-name: tokio
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: escargot
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: jsonschema
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-12 20:01:35 +09:00
Firstyear
dfbcfa865f
UI/Feature polish (#3191)
Post release some small user issues arose

* Optimise the autofocus for logins with passkeys to limit clicks
* Sort login mechs by strength
* Fix cookies to persist between browser restarts
2024-11-10 04:02:27 +00:00
Firstyear
1218abd8c6
Prevent Invalid MFA Reg States (#3194) 2024-11-10 03:36:28 +00:00
George Wu
ab4291e8d2
Change CSS for applications so SVG scales nicely in Firefox. (#3200) 2024-11-10 00:00:31 +00:00
Firstyear
9973385381
20241109 3185 max age (#3196) 2024-11-10 06:20:15 +09:00
Firstyear
0f3f604ba0
Hoist max_age to prevent incorrect deserialisation (#3190) 2024-11-09 13:28:29 +09:00
Firstyear
4f87ee2fc8
Use correct oauth2 manage acp (#3186) 2024-11-08 01:31:35 +00:00
Firstyear
a7394e8875
Re-migrate all acps to force updating (#3184)
* Re-migrate all acps to force updating

* Update server/lib/src/server/migrations.rs

---------

Co-authored-by: James Hodgkinson <james@terminaloutcomes.com>
2024-11-07 18:52:42 +09:00
dependabot[bot]
b3c6eea4e9
Bump the all group across 1 directory with 2 updates (#3180)
Bumps the all group with 2 updates in the /pykanidm directory: [mkdocs-material](https://github.com/squidfunk/mkdocs-material) and [ruff](https://github.com/astral-sh/ruff).


Updates `mkdocs-material` from 9.5.42 to 9.5.44
- [Release notes](https://github.com/squidfunk/mkdocs-material/releases)
- [Changelog](https://github.com/squidfunk/mkdocs-material/blob/master/CHANGELOG)
- [Commits](https://github.com/squidfunk/mkdocs-material/compare/9.5.42...9.5.44)

Updates `ruff` from 0.7.1 to 0.7.2
- [Release notes](https://github.com/astral-sh/ruff/releases)
- [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md)
- [Commits](https://github.com/astral-sh/ruff/compare/0.7.1...0.7.2)

---
updated-dependencies:
- dependency-name: mkdocs-material
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: ruff
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: all
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-07 04:53:05 +00:00
Firstyear
853f787327
security - low - fault in migrations (#3182)
A fault existed in the server's internal migration code, where attributes
that were multivalued would be merged rather than replaced in certain
contexts. This migration path is used for access controls, meaning that
on upgrades, attributes that were meant to be removed from access
controls or changes to access control target groups were not reflected
during the upgrade process.

This has a potentially low security impact as it may have allowed
users to change their name/displayname even if the administrator
had disable the name_self_write access control.
2024-11-07 14:32:37 +10:00
pando85
5572497909
fix(kanidmd): Print replication cert to stdout (#3179)
ShowReplicationCertificate was printing the certificate to stderr
which is not consistent with the rest of the output commands.
2024-11-07 00:30:24 +00:00
Firstyear
fbbe10e295
Correct missing CSP header (#3177) 2024-11-05 14:48:11 +10:00
Firstyear
c96e9772c7
Resolve pam services not always having a tty (#3176) 2024-11-05 00:49:33 +00:00
Firstyear
ea1fcf59e5
Resolve incorrect handling of rhost in pam (#3171) 2024-11-03 00:13:26 +00:00
CEbbinghaus
1b58e4169a
chore: Made oauth2 scopes required in CLI (#3165) 2024-11-01 01:59:27 +00:00
micolous
cc7530aa65
More "choosing a domain" revision (#3161)
* More "choosing a domain" revision:

* Link to the domain rename process
* Add some hyphens to make things easier to read
* Move the OAuth 2.0 domain sharing guidance into the origin section
* Add DNS -> IP as a potential issue
* Discourage requesting public suffix list inclusion as a workaround

* Add "own hostname" section
2024-10-30 01:48:46 +00:00
dependabot[bot]
d174cbfd72
Bump jsonschema from 0.21.0 to 0.26.0 in the all group (#3157)
* Bump jsonschema from 0.21.0 to 0.26.0 in the all group

Bumps the all group with 1 update: [jsonschema](https://github.com/Stranger6667/jsonschema).


Updates `jsonschema` from 0.21.0 to 0.26.0
- [Release notes](https://github.com/Stranger6667/jsonschema/releases)
- [Changelog](https://github.com/Stranger6667/jsonschema/blob/master/CHANGELOG.md)
- [Commits](https://github.com/Stranger6667/jsonschema/compare/rust-v0.21.0...rust-v0.26.0)

---
updated-dependencies:
- dependency-name: jsonschema
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: all
...

Signed-off-by: dependabot[bot] <support@github.com>

* fixing up change in JSONschema errors

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: James Hodgkinson <james@terminaloutcomes.com>
Co-authored-by: Firstyear <william@blackhats.net.au>
2024-10-30 01:31:48 +00:00
George Wu
fbb3b6b2db
Update missing inputmode numeric when adding a new TOTP. (#3160) 2024-10-29 12:57:24 +00:00
Firstyear
ce31abeeb0
Improve OAuth2 authorisation ux (#3158)
- Resolve an issue where oauth2 could trigger the login page to
  incorrectly redirect to an oauth2 application instead of apps
- Add indication of what client application we are accessing
  if the session is not yet authenticated
2024-10-29 04:56:28 +00:00
Firstyear
53dcb5265a
Fix attribute scim sync attribute naming (#3159) 2024-10-29 14:26:51 +10:00
George Wu
d2c329f330
Change to text input and use numeric mode for TOTP prompts. (#3154)
* Change to text input and use inputmode numeric for TOTP prompts.

* Fix some typos.
2024-10-27 23:57:28 +00:00
dependabot[bot]
44ddfb98f1
Bump the all group in /pykanidm with 3 updates (#3156)
Bumps the all group in /pykanidm with 3 updates: [mypy](https://github.com/python/mypy), [coverage](https://github.com/nedbat/coveragepy) and [ruff](https://github.com/astral-sh/ruff).


Updates `mypy` from 1.12.1 to 1.13.0
- [Changelog](https://github.com/python/mypy/blob/master/CHANGELOG.md)
- [Commits](https://github.com/python/mypy/compare/v1.12.1...v1.13.0)

Updates `coverage` from 7.6.3 to 7.6.4
- [Release notes](https://github.com/nedbat/coveragepy/releases)
- [Changelog](https://github.com/nedbat/coveragepy/blob/master/CHANGES.rst)
- [Commits](https://github.com/nedbat/coveragepy/compare/7.6.3...7.6.4)

Updates `ruff` from 0.7.0 to 0.7.1
- [Release notes](https://github.com/astral-sh/ruff/releases)
- [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md)
- [Commits](https://github.com/astral-sh/ruff/compare/0.7.0...0.7.1)

---
updated-dependencies:
- dependency-name: mypy
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: all
- dependency-name: coverage
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: ruff
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: all
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-28 09:18:11 +10:00
Firstyear
f7d701c344
Fix release note date and typos (#3153) 2024-10-27 13:06:11 +10:00
Firstyear
a76a0f5a6e
Begin 1.5.0 Development Cycle (#3150) 2024-10-27 01:53:24 +00:00
400 changed files with 30448 additions and 13904 deletions

11
.cargo/config.toml Normal file
View file

@ -0,0 +1,11 @@
# The default ld from glibc is impossibly slow and consumes huge amounts of
# memory. We use lld by default which often is twice as fast for significantly
# less ram consumption.
[target.x86_64-unknown-linux-gnu]
linker = "clang"
rustflags = ["-C", "link-arg=-fuse-ld=lld", "-Ctarget-cpu=native"]
[target.aarch64-unknown-linux-gnu]
linker = "clang"
rustflags = ["-C", "link-arg=-fuse-ld=lld", "-Ctarget-cpu=native"]

View file

@ -2,7 +2,8 @@
// README at: https://github.com/devcontainers/templates/tree/main/src/rust
{
"name": "Rust",
// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
// https://github.com/devcontainers/images/tree/main/src/rust
"image": "mcr.microsoft.com/devcontainers/rust:1-1-bookworm",
"features": {
},
@ -13,6 +14,11 @@
"source": "devcontainer-cargo-cache-${devcontainerId}",
"target": "/usr/local/cargo",
"type": "volume"
},
{
"source": "devcontainer-sccache-cache-${devcontainerId}",
"target": "/home/vscode/.cache/sccache",
"type": "volume"
}
],
// Features to add to the dev container. More info: https://containers.dev/features.
@ -21,7 +27,17 @@
// Use 'forwardPorts' to make a list of ports inside the container available locally.
"forwardPorts": [8443],
// Use 'postCreateCommand' to run commands after the container is created.
"postCreateCommand": "rustup update && rustup default stable && rustup component add rustfmt clippy && sudo apt-get update && sudo apt-get install -y sccache ripgrep libssl-dev pkg-config jq libpam0g-dev libudev-dev cmake build-essential && cargo install cargo-audit mdbook-mermaid mdbook && cargo install mdbook-alerts --version 0.6.4 && cargo install deno --locked"
"postCreateCommand": "./scripts/devcontainer_postcreate.sh",
// postStartCommand runs things once the container's up, in this case, we're starting sccache
"postStartCommand": "./scripts/devcontainer_poststart.sh",
// environment variables
"containerEnv": {
// "RUSTC_WRAPPER": "sccache",
// "CC":"/usr/bin/sccache /usr/bin/clang",
"SCCACHE_SERVER_UDS" : "/tmp/sccache.sock"
}
// Configure tool-specific properties.
// "customizations": {},

View file

@ -10,3 +10,4 @@ kanidmd/sampledata
Makefile
target
test.db
Dockerfile

View file

@ -2,9 +2,21 @@
root = true
[*.md]
charset = utf-8
end_of_line = lf
indent_size = 2
max_line_length = 100
trim_trailing_whitespace = true
[*.js]
tab_width = 4
max_line_length = 120
print_width = 120
[*.mjs]
tab_width = 4
max_line_length = 120
print_width = 120

View file

@ -19,19 +19,19 @@ jobs:
steps:
- uses: actions/checkout@v4
- name: Setup sccache
uses: mozilla-actions/sccache-action@v0.0.6
with:
version: "v0.4.2"
uses: mozilla-actions/sccache-action@v0.0.9
- name: Install dependencies
run: |
sudo apt-get update && \
sudo apt-get install -y \
libpam0g-dev \
libudev-dev \
libselinux1-dev \
libssl-dev \
libsystemd-dev \
libtss2-dev \
libudev-dev \
pkg-config \
tpm-udev \
libtss2-dev
tpm-udev
- name: "Run clippy"
run: cargo clippy --lib --bins --examples --all-features
fmt:
@ -39,8 +39,6 @@ jobs:
steps:
- uses: actions/checkout@v4
- name: Setup sccache
uses: mozilla-actions/sccache-action@v0.0.6
with:
version: "v0.4.2"
uses: mozilla-actions/sccache-action@v0.0.9
- name: "Run cargo fmt"
run: cargo fmt --check

View file

@ -35,9 +35,15 @@ jobs:
needs:
- set_tag_values
steps:
- uses: actions/checkout@v4
- name: Checkout repository
uses: actions/checkout@v4
with:
persist-credentials: false
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Docker metadata
id: meta
uses: docker/metadata-action@v5
- name: Build kanidm
uses: docker/build-push-action@v6
with:
@ -47,6 +53,9 @@ jobs:
build-args: |
"KANIDM_FEATURES="
file: tools/Dockerfile
context: .
labels: ${{ steps.meta.outputs.labels }}
annotations: ${{ steps.meta.outputs.annotations }}
# Must use OCI exporter for multi-arch: https://github.com/docker/buildx/pull/1813
outputs: type=oci,dest=/tmp/kanidm-docker.tar
- name: Upload artifact
@ -60,8 +69,8 @@ jobs:
# This step is split so that we don't apply "packages: write" permission
# except when uploading the final Docker image to GHCR.
runs-on: ubuntu-latest
if: ( github.ref_type == 'tag' || github.ref == 'refs/heads/master' ) && github.repository == 'kanidm/kanidm'
needs: kanidm_build
if: ( github.ref_type == 'tag' || github.ref == 'refs/heads/master' )
needs: [kanidm_build, set_tag_values]
permissions:
packages: write
@ -71,10 +80,11 @@ jobs:
with:
name: kanidm-docker
path: /tmp
- name: Set up ORAS
uses: oras-project/setup-oras@v1
- name: Push image to GHCR
run: |
echo "${{ secrets.GITHUB_TOKEN }}" | \
oras login -u "${{ github.actor }}" --password-stdin ghcr.io
oras copy --from-oci-layout "/tmp/kanidm-docker.tar:devel" \
"ghcr.io/${{ github.repository_owner }}/kanidm:devel"
"ghcr.io/${{ needs.set_tag_values.outputs.owner_lc }}/kanidm:devel"

View file

@ -35,27 +35,15 @@ jobs:
runs-on: ubuntu-latest
needs: set_tag_values
steps:
- uses: actions/checkout@v4
- name: Checkout repository
uses: actions/checkout@v4
with:
persist-credentials: false
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Docker metadata
id: meta
uses: docker/metadata-action@v5
with:
# list of Docker images to use as base name for tags
# images: |
# kanidm/kanidmd
# ghcr.io/username/app
# generate Docker tags based on the following events/attributes
tags: |
type=schedule
type=ref,event=branch
type=ref,event=pr
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=semver,pattern={{major}}
type=sha
- name: Build kanidmd
uses: docker/build-push-action@v6
with:
@ -64,6 +52,9 @@ jobs:
# build-args: |
# "KANIDM_BUILD_OPTIONS=-j1"
file: server/Dockerfile
context: .
labels: ${{ steps.meta.outputs.labels }}
annotations: ${{ steps.meta.outputs.annotations }}
# Must use OCI exporter for multi-arch: https://github.com/docker/buildx/pull/1813
outputs: type=oci,dest=/tmp/kanidmd-docker.tar
- name: Upload artifact
@ -77,8 +68,8 @@ jobs:
# This step is split so that we don't apply "packages: write" permission
# except when uploading the final Docker image to GHCR.
runs-on: ubuntu-latest
if: ( github.ref_type== 'tag' || github.ref == 'refs/heads/master' ) && github.repository == 'kanidm/kanidm'
needs: kanidmd_build
if: ( github.ref_type== 'tag' || github.ref == 'refs/heads/master' )
needs: [kanidmd_build, set_tag_values]
permissions:
packages: write
@ -88,10 +79,11 @@ jobs:
with:
name: kanidmd-docker
path: /tmp
- name: Set up ORAS
uses: oras-project/setup-oras@v1
- name: Push image to GHCR
run: |
echo "${{ secrets.GITHUB_TOKEN }}" | \
oras login -u "${{ github.actor }}" --password-stdin ghcr.io
oras copy --from-oci-layout "/tmp/kanidmd-docker.tar:devel" \
"ghcr.io/${{ github.repository_owner }}/kanidmd:devel"
"ghcr.io/${{ needs.set_tag_values.outputs.owner_lc }}/kanidmd:devel"

View file

@ -35,17 +35,26 @@ jobs:
runs-on: ubuntu-latest
needs: set_tag_values
steps:
- uses: actions/checkout@v4
- name: Checkout repository
uses: actions/checkout@v4
with:
persist-credentials: false
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Docker metadata
id: meta
uses: docker/metadata-action@v5
- name: Build radius
uses: docker/build-push-action@v6
with:
platforms: linux/arm64,linux/amd64
tags: ghcr.io/${{ needs.set_tag_values.outputs.owner_lc }}/radius:devel,ghcr.io/${{ needs.set_tag_values.outputs.owner_lc }}/radius:${{ needs.set_tag_values.outputs.ref_name}}
file: rlm_python/Dockerfile
context: .
labels: ${{ steps.meta.outputs.labels }}
annotations: ${{ steps.meta.outputs.annotations }}
# Must use OCI exporter for multi-arch: https://github.com/docker/buildx/pull/1813
outputs: type=oci,dest=/tmp/radius-docker.tar
- name: Upload artifact
@ -59,8 +68,8 @@ jobs:
# This step is split so that we don't apply "packages: write" permission
# except when uploading the final Docker image to GHCR.
runs-on: ubuntu-latest
if: ( github.ref_type == 'tag' || github.ref == 'refs/heads/master' ) && github.repository == 'kanidm/kanidm'
needs: radius_build
if: ( github.ref_type == 'tag' || github.ref == 'refs/heads/master' )
needs: [radius_build, set_tag_values]
permissions:
packages: write
@ -70,7 +79,8 @@ jobs:
with:
name: radius-docker
path: /tmp
- name: Set up ORAS
uses: oras-project/setup-oras@v1
# Docker won't directly import OCI images and keep their multi-arch
# features, but ORAS will: https://oras.land/docs/commands/oras_copy
- name: Push image to GHCR
@ -78,4 +88,4 @@ jobs:
echo "${{ secrets.GITHUB_TOKEN }}" | \
oras login -u "${{ github.actor }}" --password-stdin ghcr.io
oras copy --from-oci-layout "/tmp/radius-docker.tar:devel" \
"ghcr.io/${{ github.repository_owner }}/radius:devel"
"ghcr.io/${{ needs.set_tag_values.outputs.owner_lc }}/radius:devel"

21
.github/workflows/javascript_lint.yml vendored Normal file
View file

@ -0,0 +1,21 @@
---
name: Javascript Linting
"on":
- push
- pull_request
jobs:
javascript_lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run ESLint to check Javascript files
run:
make eslint
javascript_fmt:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run Prettier to check Javascript files
run:
make prettier

View file

@ -24,9 +24,7 @@ jobs:
with:
ref: ${{ inputs.tag }}
- name: Setup sccache
uses: mozilla-actions/sccache-action@v0.0.6
with:
version: "v0.4.2"
uses: mozilla-actions/sccache-action@v0.0.9
- name: Install deps
run: |
sudo apt-get update

View file

@ -27,20 +27,18 @@ jobs:
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
- name: Setup sccache
uses: mozilla-actions/sccache-action@v0.0.6
with:
version: "v0.4.2"
uses: mozilla-actions/sccache-action@v0.0.9
- name: Install dependencies
run: |
sudo apt-get update && \
sudo apt-get install -y \
libpam0g-dev \
libudev-dev \
libssl-dev
libssl-dev \
libsystemd-dev
- name: "Build the workspace"
run: cargo build --workspace
run: cargo build --locked --workspace
- name: "Check disk space and size of target, then clean it"
run: |
df -h
@ -74,20 +72,18 @@ jobs:
with:
toolchain: ${{ matrix.rust_version }}
- name: Setup sccache
uses: mozilla-actions/sccache-action@v0.0.6
with:
version: "v0.4.2"
uses: mozilla-actions/sccache-action@v0.0.9
- name: Install dependencies
run: |
sudo apt-get update && \
sudo apt-get install -y \
libpam0g-dev \
libudev-dev \
libssl-dev
libssl-dev \
libsystemd-dev
- name: "Build the workspace"
run: cargo build --workspace
run: cargo build --locked --workspace
- name: "Check disk space and size of target, then clean it"
run: |
df -h
@ -116,10 +112,7 @@ jobs:
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
- name: Setup sccache
uses: mozilla-actions/sccache-action@v0.0.6
with:
version: "v0.4.2"
uses: mozilla-actions/sccache-action@v0.0.9
- name: Install dependencies
run: |
sudo apt-get update && \
@ -127,6 +120,7 @@ jobs:
libpam0g-dev \
libudev-dev \
libssl-dev \
libsystemd-dev \
ripgrep
- name: "Run the release build test script"
env:

View file

@ -28,9 +28,7 @@ jobs:
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
- name: Setup sccache
uses: mozilla-actions/sccache-action@v0.0.6
with:
version: "v0.4.2"
- run: cargo build -p kanidm_client -p kanidm_tools --bin kanidm
uses: mozilla-actions/sccache-action@v0.0.9
- run: cargo build --locked -p kanidm_client -p kanidm_tools --bin kanidm
# yamllint disable-line rule:line-length
- run: cargo test -p kanidm_client -p kanidm_tools

9
.gitignore vendored
View file

@ -17,9 +17,12 @@ tools/orca/example_profiles/small/orca-edited.toml
/docs/
# webui things we don't need
*.d.ts
server/web_ui/*/pkg/*.js
# coverage-related things
*.profraw
tarpaulin-report.html
# kanidm simple packaging
deployment-config/
kanidm_simple_pkg/
@ -35,9 +38,13 @@ pykanidm/site/
# oauth2 integration test things
scripts/oauth_proxy/client.secret
scripts/oauth_proxy/envfile
# local config things
.envrc
# IDEs
.idea/
.vscode/
# javascript test things
node_modules/

View file

@ -1,2 +1,4 @@
# yale-mistakes were made
/pykanidm/* @yaleman
# Least qualified nix guy :P
shell.nix @cebbinghaus

View file

@ -44,6 +44,9 @@
- adamcstephens
- Chris Olstrom (colstrom)
- Christopher-Robin (cebbinghaus)
- Fabian Kammel (datosh)
- Andris Raugulis (arthepsy)
- Jason (argonaut0)
## Acknowledgements

2440
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -1,10 +1,10 @@
[workspace.package]
version = "1.4.0-dev"
version = "1.6.0-dev"
authors = [
"William Brown <william@blackhats.net.au>",
"James Hodgkinson <james@terminaloutcomes.com>",
]
rust-version = "1.79"
rust-version = "1.80"
edition = "2021"
license = "MPL-2.0"
homepage = "https://github.com/kanidm/kanidm/"
@ -120,28 +120,30 @@ codegen-units = 256
# kanidm-hsm-crypto = { path = "../hsm-crypto" }
[workspace.dependencies]
kanidmd_core = { path = "./server/core", version = "=1.4.0-dev" }
kanidmd_lib = { path = "./server/lib", version = "=1.4.0-dev" }
kanidmd_lib_macros = { path = "./server/lib-macros", version = "=1.4.0-dev" }
kanidmd_testkit = { path = "./server/testkit", version = "=1.4.0-dev" }
kanidm_build_profiles = { path = "./libs/profiles", version = "=1.4.0-dev" }
kanidm_client = { path = "./libs/client", version = "=1.4.0-dev" }
kanidm-hsm-crypto = "^0.2.0"
kanidm_lib_crypto = { path = "./libs/crypto", version = "=1.4.0-dev" }
kanidm_lib_file_permissions = { path = "./libs/file_permissions", version = "=1.4.0-dev" }
kanidm_proto = { path = "./proto", version = "=1.4.0-dev" }
kanidm_unix_common = { path = "./unix_integration/common", version = "=1.4.0-dev" }
kanidm_utils_users = { path = "./libs/users", version = "=1.4.0-dev" }
scim_proto = { path = "./libs/scim_proto", version = "=1.4.0-dev" }
sketching = { path = "./libs/sketching", version = "=1.4.0-dev" }
libnss = { git = "https://github.com/Firstyear/libnss-rs.git", branch = "20250207-freebsd" }
anyhow = { version = "1.0.90" }
[workspace.dependencies]
kanidmd_core = { path = "./server/core", version = "=1.6.0-dev" }
kanidmd_lib = { path = "./server/lib", version = "=1.6.0-dev" }
kanidmd_lib_macros = { path = "./server/lib-macros", version = "=1.6.0-dev" }
kanidmd_testkit = { path = "./server/testkit", version = "=1.6.0-dev" }
kanidm_build_profiles = { path = "./libs/profiles", version = "=1.6.0-dev" }
kanidm_client = { path = "./libs/client", version = "=1.6.0-dev" }
kanidm-hsm-crypto = "^0.2.0"
kanidm_lib_crypto = { path = "./libs/crypto", version = "=1.6.0-dev" }
kanidm_lib_file_permissions = { path = "./libs/file_permissions", version = "=1.6.0-dev" }
kanidm_proto = { path = "./proto", version = "=1.6.0-dev" }
kanidm_unix_common = { path = "./unix_integration/common", version = "=1.6.0-dev" }
kanidm_utils_users = { path = "./libs/users", version = "=1.6.0-dev" }
scim_proto = { path = "./libs/scim_proto", version = "=1.6.0-dev" }
sketching = { path = "./libs/sketching", version = "=1.6.0-dev" }
anyhow = { version = "1.0.95" }
argon2 = { version = "0.5.3", features = ["alloc"] }
askama = { version = "0.12.1", features = ["serde", "with-axum"] }
askama_axum = { version = "0.4.0" }
async-trait = "^0.1.83"
axum = { version = "0.7.7", features = [
async-trait = "^0.1.85"
axum = { version = "0.7.9", features = [
"form",
"json",
"macros",
@ -154,41 +156,41 @@ axum = { version = "0.7.7", features = [
axum-htmx = { version = "0.5.0", features = ["serde", "guards"] }
base32 = "^0.5.1"
base64 = "^0.22.1"
base64urlsafedata = "0.5.0"
bitflags = "^2.6.0"
bytes = "^1.7.2"
clap = { version = "^4.5.20", features = ["derive", "env"] }
clap_complete = "^4.5.33"
base64urlsafedata = "0.5.1"
bitflags = "^2.8.0"
bytes = "^1.9.0"
clap = { version = "^4.5.34", features = ["derive", "env"] }
clap_complete = "^4.5.42"
# Forced by saffron/cron
chrono = "^0.4.35"
chrono = "^0.4.39"
compact_jwt = { version = "^0.4.2", default-features = false }
concread = "^0.5.3"
cron = "0.12.1"
concread = "^0.5.5"
cron = "0.15.0"
crossbeam = "0.8.4"
csv = "1.3.0"
dialoguer = "0.10.4"
csv = "1.3.1"
dialoguer = "0.11.0"
dhat = "0.3.3"
dyn-clone = "^1.0.17"
fernet = "^0.2.1"
filetime = "^0.2.24"
fs4 = "^0.8.3"
fs4 = "^0.13.0"
futures = "^0.3.31"
futures-util = { version = "^0.3.30", features = ["sink"] }
gix = { version = "0.64.0", default-features = false }
hashbrown = { version = "0.14.3", features = ["serde", "inline-more", "ahash"] }
hex = "^0.4.3"
http = "1.1.0"
hyper = { version = "1.5.0", features = [
http = "1.2.0"
hyper = { version = "1.5.1", features = [
"full",
] } # hyper full includes client/server/http2
hyper-util = { version = "0.1.9", features = ["server", "tokio"] }
hyper-util = { version = "0.1.10", features = ["server", "tokio"] }
idlset = "^0.2.5"
image = { version = "0.24.9", default-features = false, features = [
"gif",
"jpeg",
"webp",
] }
itertools = "0.13.0"
itertools = "0.14.0"
enum-iterator = "2.1.0"
kanidmd_web_ui_shared = { path = "./server/web_ui/shared" }
# REMOVE this
@ -196,60 +198,63 @@ lazy_static = "^1.5.0"
ldap3_client = "^0.5.2"
ldap3_proto = { version = "^0.5.2", features = ["serde"] }
libc = "^0.2.161"
libc = "^0.2.168"
libnss = "^0.8.0"
libsqlite3-sys = "^0.25.2"
lodepng = "3.10.7"
lru = "^0.12.5"
lodepng = "3.11.0"
lru = "^0.13.0"
mathru = "^0.13.0"
md-5 = "0.10.6"
mimalloc = "0.1.43"
notify-debouncer-full = { version = "0.1" }
notify-debouncer-full = { version = "0.5" }
num_enum = "^0.5.11"
oauth2_ext = { version = "^4.4.2", package = "oauth2", default-features = false }
openssl-sys = "^0.9"
openssl = "^0.10.68"
openssl = "^0.10.72"
opentelemetry = { version = "0.20.0" }
opentelemetry_api = { version = "0.20.0", features = ["logs", "metrics"] }
opentelemetry-otlp = { version = "0.13.0", default-features = false, features = [
opentelemetry = { version = "0.27.0" }
opentelemetry_api = { version = "0.27.0", features = ["logs", "metrics"] }
opentelemetry-otlp = { version = "0.27.0", default-features = false, features = [
"serde",
"logs",
"metrics",
"http-proto",
"grpc-tonic",
] }
opentelemetry_sdk = "0.20.0"
tracing-opentelemetry = "0.21.0"
opentelemetry_sdk = { version = "0.27.0", features = ["rt-tokio"] }
opentelemetry-semantic-conventions = "0.27.0"
tracing-opentelemetry = "0.28.0"
tracing-core = "0.1.33"
paste = "^1.0.14"
peg = "0.8"
pkg-config = "^0.3.31"
prctl = "1.0.0"
proc-macro2 = "1.0.88"
proc-macro2 = "1.0.93"
qrcode = "^0.12.0"
quote = "1"
rand = "^0.8.5"
rand_chacha = "0.3.1"
regex = "1.11.0"
reqwest = { version = "0.12.8", default-features = false, features = [
reqwest = { version = "0.12.12", default-features = false, features = [
"cookies",
"http2",
"json",
"gzip",
"rustls-tls-native-roots",
"rustls-tls-native-roots-no-provider",
] }
rusqlite = { version = "^0.28.0", features = ["array", "bundled"] }
rustls = { version = "0.23.13", default-features = false, features = [
rustls = { version = "0.23.21", default-features = false, features = [
"aws_lc_rs",
] }
sd-notify = "^0.4.3"
sd-notify = "^0.4.5"
selinux = "^0.4.6"
serde = "^1.0.210"
serde = "^1.0.217"
serde_cbor = { version = "0.12.0-dev", package = "serde_cbor_2" }
serde_json = "^1.0.132"
serde_json = "^1.0.137"
serde_urlencoded = "^0.7.1"
serde_with = "3.11.0"
serde_with = "3.12.0"
sha-crypt = "0.5.0"
sha2 = "0.10.8"
shellexpand = "^2.1.2"
@ -258,39 +263,38 @@ smolset = "^1.3.1"
sshkey-attest = "^0.5.0"
sshkeys = "0.3.3"
svg = "0.13.1"
syn = { version = "2.0.82", features = ["full"] }
tempfile = "3.13.0"
syn = { version = "2.0.96", features = ["full"] }
tempfile = "3.15.0"
testkit-macros = { path = "./server/testkit-macros" }
time = { version = "^0.3.34", features = ["formatting", "local-offset"] }
time = { version = "^0.3.36", features = ["formatting", "local-offset"] }
tokio = "^1.40.0"
tokio = "^1.44.2"
tokio-openssl = "^0.6.5"
tokio-util = "^0.7.12"
tokio-util = "^0.7.13"
toml = "^0.5.11"
tracing = { version = "^0.1.40", features = [
tracing = { version = "^0.1.41", features = [
"max_level_trace",
"release_max_level_debug",
] }
tracing-subscriber = { version = "^0.3.18", features = ["env-filter"] }
tracing-subscriber = { version = "^0.3.19", features = ["env-filter"] }
tracing-forest = "^0.1.6"
url = "^2.5.2"
urlencoding = "2.1.3"
utoipa = { version = "4.2.0", features = ["url", "uuid"] }
utoipa-swagger-ui = "6.0.0"
uuid = "^1.11.0"
uuid = "^1.12.1"
webauthn-authenticator-rs = { version = "0.5.0", features = [
webauthn-authenticator-rs = { version = "0.5.1", features = [
"softpasskey",
"softtoken",
"mozilla",
] }
webauthn-rs = { version = "0.5.0", features = ["preview-features"] }
webauthn-rs-core = "0.5.0"
webauthn-rs-proto = "0.5.0"
webauthn-rs = { version = "0.5.1", features = ["preview-features"] }
webauthn-rs-core = "0.5.1"
webauthn-rs-proto = "0.5.1"
whoami = "^1.5.2"
whoami = "^1.6.0"
walkdir = "2"
x509-cert = "0.2.5"
@ -298,4 +302,3 @@ x509-cert = "0.2.5"
zxcvbn = "^2.2.2"
nonempty = "0.8.1"

View file

@ -178,11 +178,8 @@ codespell:
--skip='*.svg' \
--skip='*.br' \
--skip='./rlm_python/mods-available/eap' \
--skip='./server/web_ui/static/external' \
--skip='./server/web_ui/pkg/external' \
--skip='./server/web_ui/shared/static/external' \
--skip='./server/web_ui/admin/static/external,./server/web_ui/admin/pkg/external' \
--skip='./server/lib/src/constants/system_config.rs,./pykanidm/site,./server/lib/src/constants/*.json'
--skip='./server/lib/src/constants/system_config.rs' \
--skip='./pykanidm/site'
.PHONY: test/pykanidm/pytest
test/pykanidm/pytest: ## python library testing
@ -316,26 +313,44 @@ cert/clean:
rm -f /tmp/kanidm/ca.txt*
rm -f /tmp/kanidm/ca.{cnf,srl,srl.old}
.PHONY: rust/coverage
coverage/test: ## Run coverage tests
coverage/test:
LLVM_PROFILE_FILE="$(PWD)/target/profile/coverage-%p-%m.profraw" RUSTFLAGS="-C instrument-coverage" cargo test $(TESTS)
.PHONY: coverage/grcov
coverage/grcov: ## Run grcov
coverage/grcov:
rm -rf ./target/coverage/html
grcov . --binary-path ./target/debug/deps/ \
-s . \
-t html \
--branch \
--ignore-not-existing \
--ignore '../*' \
--ignore "/*" \
--ignore "target/*" \
-o target/coverage/html
.PHONY: coverage
coverage: ## Run all the coverage tests
coverage: coverage/test coverage/grcov
echo "Coverage report is in ./target/coverage/html/index.html"
coverage: ## Run the coverage tests using cargo-tarpaulin
cargo tarpaulin --out Html
@echo "Coverage file at file://$(PWD)/tarpaulin-report.html"
.PHONY: coveralls
coveralls: ## Run cargo tarpaulin and upload to coveralls
coveralls:
cargo tarpaulin --coveralls $(COVERALLS_REPO_TOKEN)
@echo "Coveralls repo information is at https://coveralls.io/github/kanidm/kanidm"
.PHONY: eslint
eslint: ## Run eslint on the UI javascript things
eslint: eslint/setup
@echo "################################"
@echo " Running eslint..."
@echo "################################"
cd server/core && find ./static -name '*js' -not -path '*/external/*' -exec eslint "{}" \;
@echo "################################"
@echo "Done!"
.PHONY: eslint/setup
eslint/setup: ## Install eslint for the UI javascript things
cd server/core && npm ci
.PHONY: prettier
prettier: ## Run prettier on the UI javascript things
prettier: eslint/setup
@echo " Running prettier..."
cd server/core && npm run prettier
@echo "Done!"
.PHONY: prettier/fix
prettier/fix: ## Run prettier on the UI javascript things and write back changes
prettier/fix: eslint/setup
@echo " Running prettier..."
cd server/core && npm run prettier:fix
@echo "Done!"

View file

@ -1,8 +1,6 @@
# Kanidm - Simple and Secure Identity Management
<p align="center">
<img src="https://raw.githubusercontent.com/kanidm/kanidm/master/artwork/logo-small.png" width="20%" height="auto" />
</p>
![Kanidm Logo](artwork/logo-small.png)
## About

View file

@ -1,42 +1,93 @@
<p align="center">
<img src="https://raw.githubusercontent.com/kanidm/kanidm/master/artwork/logo-small.png" width="20%" height="auto" />
</p>
# Kanidm Release Notes
# Getting Started
![Kanidm Logo](artwork/logo-small.png)
## Getting Started
To get started, see the [kanidm book]
# Feedback
## Feedback
We value your feedback! First, please see our [code of conduct]. If you have questions please join
our [gitter community channel] so that we can help. If you find a bug or issue, we'd love you to
report it to our [issue tracker].
# Release Notes
## Release Notes
## 2024-08-07 - Kanidm 1.4.0
### 2025-02-09 - Kanidm 1.5.0
This is the latest stable release of the Kanidm Identity Management project. Every release is the
combined effort of our community and we appreciate their invaluable contributions, comments,
questions, feedback and support.
You should review our
[support documentation](https://github.com/kanidm/kanidm/blob/master/book/src/support.md) as this
[support documentation] as this
may have important effects on your distribution or upgrades in future.
Before upgrading you should review
[our upgrade documentation](https://github.com/kanidm/kanidm/blob/master/book/src/server_updates.md#general-update-notes)
[our upgrade documentation]
### 1.4.0 Important Changes
#### 1.5.0 Important Changes
- There has been a lot of tweaks to how cookies are handled in this release, if you're having issues with the login flow please clear all cookies as an initial troubleshooting step.
#### 1.5.0 Release Highlights
- Many updates to the UI!
- SSH Keys in Credentials Update (#3027)
- Improved error message when PassKey is missing PIN (mainly for Firefox) (#3403)
- Fix the password reset form and possible resolver issue (#3398)
- Fixed unrecoverable error page doesn't include logo or domain name (#3352)
- Add support for prefers-color-scheme using Bootstrap classes. Dark mode! (#3327)
- Automatically trigger passkeys on login view (#3307)
- Two new operating systems!
- Initial OpenBSD support (#3381)
- FreeBSD client (#3333)
- Many SCIM-related improvements
- SCIM access control (#3359)
- SCIM put (#3151)
- OAuth2 Things
- Allow OAuth2 with empty `state` parameter (#3396)
- Allow POST on oauth userinfo (#3395)
- Add OAuth2 `response_mode=fragment` (#3335)
- Add CORS headers to jwks and userinfo (#3283)
- Allowing SPN query with non-SPN structured data in LDAP (#3400)
- Correctly return that uuid2spn changed on domain rename (#3402)
- RADIUS startup fixing (#3388)
- Repaired systemd reload notifications (#3355)
- Add `ssh_publickeys` as a claim for OAuth2 (#3346)
- Allow modification of password minimum length (#3345)
- PAM on Debian, enable use_first_pass by default (#3326)
- Allow opt-in of easter eggs (#3308)
- Allow reseting account policy values to defaults (#3306)
- Ignore system users for UPG synthesiseation (#3297)
- Allow group managers to modify entry-managed-by (#3272)
And many more!
### 2024-11-01 - Kanidm 1.4.0
This is the latest stable release of the Kanidm Identity Management project. Every release is the
combined effort of our community and we appreciate their invaluable contributions, comments,
questions, feedback and support.
You should review our
[support documentation] as this
may have important effects on your distribution or upgrades in future.
Before upgrading you should review
[our upgrade documentation]
#### 1.4.0 Important Changes
- The web user interface has been rewritten and now supports theming. You will notice that your
domain displayname is included in a number of locations on upgrade, and that you can set
your own domain and OAuth2 client icons.
- OAuth2 strict redirect uri is now required. Ensure you have read
[our upgrade documentation](https://github.com/kanidm/kanidm/blob/master/book/src/server_updates.md#general-update-notes).
[our upgrade documentation].
and taken the needed steps before upgrading.
### 1.4.0 Release Highlights
#### 1.4.0 Release Highlights
- Improve handling of client timeouts when the server is under high load
- Resolve a minor issue preventing some credential updates from saving
@ -63,22 +114,22 @@ and taken the needed steps before upgrading.
- SCIM foundations for getting and modifying entries, reference handling, and complex attribute
display. Much more to come in this space!
- Rewrite the entire web frontend to be simpler and faster, allowing more features to be added
in future. Greatly improves user expirence as the pages are now very fast to load!
in the future. Greatly improves user experience as the pages are now very fast to load!
## 2024-08-07 - Kanidm 1.3.0
### 2024-08-07 - Kanidm 1.3.0
This is the latest stable release of the Kanidm Identity Management project. Every release is the
combined effort of our community and we appreciate their invaluable contributions, comments,
questions, feedback and support.
You should review our
[support documentation](https://github.com/kanidm/kanidm/blob/master/book/src/support.md) as this
[support documentation] as this
may have important effects on your distribution or upgrades in future.
Before upgrading you should review
[our upgrade documentation](https://github.com/kanidm/kanidm/blob/master/book/src/server_updates.md#general-update-notes)
[our upgrade documentation]
### 1.3.0 Important Changes
#### 1.3.0 Important Changes
- New GID number constraints are now enforced in this version. To upgrade from 1.2.0 all accounts
and groups must adhere to these rules. See [our upgrade documentation]. about tools to help you
@ -89,7 +140,7 @@ Before upgrading you should review
by PassKeys which give a better user experience.
- Kanidm now supports FreeBSD and Illumos in addition to Linux
### 1.3.0 Release Highlights
#### 1.3.0 Release Highlights
- TOTP update user interface improvements
- Improved error messages when a load balancer is failing
@ -112,24 +163,24 @@ Before upgrading you should review
- Strict redirect URI enforcement in OAuth2
- Substring indexing for improved search performance
## 2024-05-01 - Kanidm 1.2.0
### 2024-05-01 - Kanidm 1.2.0
This is the first stable release of the Kanidm Identity Management project. We want to thank every
one in our community who has supported to the project to this point with their invaluable
contributions, comments, questions, feedback and support.
Importantly this release makes a number of changes to our project's support processes. You should
review our [support documentation](https://github.com/kanidm/kanidm/blob/master/book/src/support.md)
review our [support documentation]
as this may have important effects on your distribution or upgrades in future.
### 1.2.0 Important Changes
#### 1.2.0 Important Changes
- On upgrade all OAuth2 sessions and user sessions will be reset due to changes in cryptographic key
handling. This does not affect api tokens.
- There is a maximum limit of 48 interactive sessions for persons where older sessions are
automatically removed.
### 1.2.0 Release Highlights
#### 1.2.0 Release Highlights
- The book now contains a list of supported RFCs and standards
- Add code challenge methods to OIDC discovery
@ -154,7 +205,7 @@ as this may have important effects on your distribution or upgrades in future.
- Migrate cryptographic key handling to an object model with future HSM support
- Limit maximum active sessions on an account to 48
## 2024-02-07 - Kanidm 1.1.0-rc.16
### 2024-02-07 - Kanidm 1.1.0-rc.16
This is the sixteenth pre-release of the Kanidm Identity Management project. Pre-releases are to
help get feedback and ideas from the community on how we can continue to make this project better.
@ -163,7 +214,7 @@ This is the final release candidate before we publish a release version. We beli
server interfaces are stable and reliable enough for people to depend on, and to develop external
tools to interact with Kanidm.
### 1.1.0-rc.16 Release Highlights
#### 1.1.0-rc.16 Release Highlights
- Replication for two node environments is now supported
- Account policy supports password minimum length
@ -182,7 +233,7 @@ tools to interact with Kanidm.
- Support RFC6749 Client Credentials Grant
- Support custom claim maps in OIDC
## 2023-10-31 - Kanidm 1.1.0-beta14
### 2023-10-31 - Kanidm 1.1.0-beta14
This is the fourteenth pre-release of the Kanidm Identity Management project. Pre-releases are to
help get feedback and ideas from the community on how we can continue to make this project better.
@ -191,7 +242,7 @@ At this point we believe we are on the final stretch to making something we cons
ready". After this we will start to ship release candidates as our focus will now be changing to
finish our production components and the stability of the API's for longer term support.
### 1.1.0-beta14 Release Highlights
#### 1.1.0-beta14 Release Highlights
- Replication is in Beta! Please test carefully!
- Web UI WASM has been split up, significantly improving the responsiveness.
@ -205,7 +256,7 @@ finish our production components and the stability of the API's for longer term
- Removed a lot of uses of `unwrap` and `expect` to improve reliability.
- Account policy framework is now in place.
## 2023-05-01 - Kanidm 1.1.0-beta13
### 2023-05-01 - Kanidm 1.1.0-beta13
This is the thirteenth pre-release of the Kanidm Identity Management project. Pre-releases are to
help get feedback and ideas from the community on how we can continue to make this project better.
@ -214,7 +265,7 @@ At this point we believe we are on the final stretch to making something we cons
ready". After this we will start to ship release candidates as our focus will now be changing to
finish our production components and the stability of the API's for longer term support.
### 1.1.0-beta13 Release Highlights
#### 1.1.0-beta13 Release Highlights
- Replication foundations
- Full implementation of replication refresh
@ -255,7 +306,7 @@ finish our production components and the stability of the API's for longer term
- Improve create-reset-token user experience
- Improve self-healing for some reference issues
## 2023-05-01 - Kanidm 1.1.0-alpha12
### 2023-05-01 - Kanidm 1.1.0-alpha12
This is the twelfth alpha series release of the Kanidm Identity Management project. Alpha releases
are to help get feedback and ideas from the community on how we can continue to make this project
@ -266,7 +317,7 @@ done so yet is we haven't decided if we want to commit to the current API layout
There are still things we want to change there. Otherwise the server is stable and reliable for
production usage.
### Release Highlights
#### 1.1.0-alpha12 Release Highlights
- Allow full server content replication in testing (yes we're finally working on replication!)
- Improve OAuth2 to allow scoped members to see RS they can access for UI flows
@ -286,7 +337,7 @@ production usage.
- Add exclusive process lock to daemon
- Allow dns/rdns in ldap search contexts
## 2023-02-01 - Kanidm 1.1.0-alpha11
### 2023-02-01 - Kanidm 1.1.0-alpha11
This is the eleventh alpha series release of the Kanidm Identity Management project. Alpha releases
are to help get feedback and ideas from the community on how we can continue to make this project
@ -296,7 +347,7 @@ The project is shaping up very nicely, and a beta will be coming soon! The main
done so yet is we haven't decided if we want to commit to the current API layout and freeze it yet.
There are still things we want to change there. Otherwise the server is stable and reliable.
### Release Highlights
#### 1.1.0-alpha11 Release Highlights
- Support /etc/skel home dir templates in kanidm-unixd
- Improve warning messages for openssl when a cryptographic routine is not supported
@ -317,7 +368,7 @@ There are still things we want to change there. Otherwise the server is stable a
- Improve the access control module to evaluate access in a clearer way
- Allow synced users to correct modify their local sessions
## 2022-11-01 - Kanidm 1.1.0-alpha10
### 2022-11-01 - Kanidm 1.1.0-alpha10
This is the tenth alpha series release of the Kanidm Identity Management project. Alpha releases are
to help get feedback and ideas from the community on how we can continue to make this project better
@ -325,12 +376,12 @@ for a future supported release.
The project is shaping up very nicely, and a beta will be coming soon!
### Upgrade Note
#### 1.1.0-alpha10 Upgrade Note
This version will _require_ TLS on all servers, even if behind a load balancer or TLS terminating
proxy. You should be ready for this change when you upgrade to the latest version.
### Release Highlights
#### 1.1.0-alpha10 Release Highlights
- Management and tracking of authenticated sessions
- Make upgrade migrations more robust when upgrading over multiple versions
@ -352,7 +403,7 @@ proxy. You should be ready for this change when you upgrade to the latest versio
- Cleanup of expired authentication sessions
- Improved administration of password badlists
## 2022-08-02 - Kanidm 1.1.0-alpha9
### 2022-08-02 - Kanidm 1.1.0-alpha9
This is the ninth alpha series release of the Kanidm Identity Management project. Alpha releases are
to help get feedback and ideas from the community on how we can continue to make this project better
@ -360,7 +411,7 @@ for a future supported release.
The project is shaping up very nicely, and a beta will be coming soon!
### Release Highlights
#### 1.1.0-alpha9 Release Highlights
- Inclusion of a Python3 API library
- Improve orca usability
@ -376,13 +427,13 @@ The project is shaping up very nicely, and a beta will be coming soon!
- CTAP2+ support in Webauthn via CLI
- Radius supports EAP TLS identities in addition to EAP PEAP
## 2022-05-01 - Kanidm 1.1.0-alpha8
### 2022-05-01 - Kanidm 1.1.0-alpha8
This is the eighth alpha series release of the Kanidm Identity Management project. Alpha releases
are to help get feedback and ideas from the community on how we can continue to make this project
better for a future supported release.
### Release Highlights
#### 1.1.0-alpha8 Release Highlights
- Foundations for cryptographic trusted device authentication
- Foundations for new user onboarding and credential reset
@ -398,13 +449,13 @@ better for a future supported release.
- Highlight that the WebUI is in alpha to prevent confusion
- Remove sync only client paths
## 2022-01-01 - Kanidm 1.1.0-alpha7
### 2022-01-01 - Kanidm 1.1.0-alpha7
This is the seventh alpha series release of the Kanidm Identity Management project. Alpha releases
are to help get feedback and ideas from the community on how we can continue to make this project
better for a future supported release.
### Release Highlights
#### 1.1.0-alpha7 Release Highlights
- OAuth2 scope to group mappings
- Webauthn subdomain support
@ -415,7 +466,7 @@ better for a future supported release.
- Addition of email address attributes
- Web UI improvements for OAuth2
## 2021-10-01 - Kanidm 1.1.0-alpha6
### 2021-10-01 - Kanidm 1.1.0-alpha6
This is the sixth alpha series release of the Kanidm Identity Management project. Alpha releases are
to help get feedback and ideas from the community on how we can continue to make this project better
@ -424,7 +475,7 @@ for a future supported release.
It's also a special release as Kanidm has just turned 3 years old! Thank you all for helping to
bring the project this far! 🎉 🦀
### Release Highlights
#### 1.1.0-alpha6 Release Highlights
- Support backup codes as MFA in case of lost TOTP/Webauthn
- Dynamic menus on CLI for usernames when multiple sessions exist
@ -444,13 +495,13 @@ bring the project this far! 🎉 🦀
- Improvements to performance with high cache sizes
- Session tokens persist over a session restart
## 2021-07-07 - Kanidm 1.1.0-alpha5
### 2021-07-07 - Kanidm 1.1.0-alpha5
This is the fifth alpha series release of the Kanidm Identity Management project. Alpha releases are
to help get feedback and ideas from the community on how we can continue to make this project better
for a future supported release.
### Release Highlights
#### 1.1.0-alpha5 Release Highlights
- Fix a major defect in how backup/restore worked
- Improve query performance by caching partial queries
@ -465,13 +516,13 @@ for a future supported release.
- Statistical analysis of indexes to improve query optimisation
- Handle broken TOTP authenticator apps
## 2021-04-01 - Kanidm 1.1.0-alpha4
### 2021-04-01 - Kanidm 1.1.0-alpha4
This is the fourth alpha series release of the Kanidm Identity Management project. Alpha releases
are to help get feedback and ideas from the community on how we can continue to make this project
better for a future supported release.
### Release Highlights
#### 1.1.0-alpha4 Release Highlights
- Performance Improvements
- TOTP CLI enrollment
@ -485,13 +536,13 @@ better for a future supported release.
- Badlist checked at login to determine account compromise
- Minor Fixes for attribute display
## 2021-01-01 - Kanidm 1.1.0-alpha3
### 2021-01-01 - Kanidm 1.1.0-alpha3
This is the third alpha series release of the Kanidm Identity Management project. Alpha releases are
to help get feedback and ideas from the community on how we can continue to make this project better
for a future supported release.
### Release Highlights
#### 1.1.0-alpha3 Release Highlights
- Account "valid from" and "expiry" times.
- Rate limiting and softlocking of account credentials to prevent bruteforcing.
@ -499,13 +550,13 @@ for a future supported release.
- Rewrite of json authentication protocol components.
- Unixd will cache "non-existent" items to improve nss/pam latency.
## 2020-10-01 - Kanidm 1.1.0-alpha2
### 2020-10-01 - Kanidm 1.1.0-alpha2
This is the second alpha series release of the Kanidm Identity Management project. Alpha releases
are to help get feedback and ideas from the community on how we can continue to make this project
better for a future supported release.
### Release Highlights
#### 1.1.0-alpha2 Release Highlights
- SIMD key lookups in container builds for datastructures
- Server and Client hardening warnings for running users and file permissions
@ -517,7 +568,7 @@ better for a future supported release.
- Reduction in memory footprint during searches
- Change authentication from cookies to auth-bearer tokens
## 2020-07-01 - Kanidm 1.1.0-alpha1
### 2020-07-01 - Kanidm 1.1.0-alpha1
This is the first alpha series release of the Kanidm Identity Management project. Alpha releases are
to help get feedback and ideas from the community on how we can continue to make this project better
@ -536,7 +587,7 @@ people. I would especially like to thank:
- Samuel Cabrero (scabrero)
- Jim McDonough
### Release Highlights
#### 1.1.0-alpha1 Release Highlights
- A working identity management server, including database
- RADIUS authentication and docker images
@ -552,3 +603,5 @@ people. I would especially like to thank:
[gitter community channel]: https://gitter.im/kanidm/community
[code of conduct]: https://github.com/kanidm/kanidm/blob/master/CODE_OF_CONDUCT.md
[kanidm book]: https://kanidm.github.io/kanidm/stable/
[our upgrade documentation]: https://github.com/kanidm/kanidm/blob/master/book/src/server_updates.md#general-update-notes
[support documentation]: https://github.com/kanidm/kanidm/blob/master/book/src/support.md

View file

@ -24,6 +24,7 @@
- [Domain Rename](domain_rename.md)
- [Monitoring the platform](monitoring_the_platform.md)
- [Recycle Bin](recycle_bin.md)
- [Customising](customising.md)
- [Accounts and Groups](accounts/intro.md)
- [People Accounts](accounts/people_accounts.md)
@ -39,9 +40,9 @@
- [Service Integrations](integrations/readme.md)
- [LDAP](integrations/ldap.md)
- [OAuth2](integrations/oauth2.md)
- [How does OAuth2 work?](integrations/oauth2/how_does_oauth2_work.md)
- [Custom Claims](integrations/oauth2/custom_claims.md)
- [Example Configurations](integrations/oauth2/examples.md)
- [How does OAuth2 work?](integrations/oauth2/how_does_oauth2_work.md)
- [PAM and nsswitch](integrations/pam_and_nsswitch.md)
- [SUSE / OpenSUSE](integrations/pam_and_nsswitch/suse.md)
- [Fedora](integrations/pam_and_nsswitch/fedora.md)
@ -52,7 +53,6 @@
- [Service Integration Examples](examples/readme.md)
- [Kubernetes Ingress](examples/kubernetes_ingress.md)
- [OAuth2 Examples](integrations/oauth2/examples.md)
- [Traefik](examples/traefik.md)
- [Replication](repl/readme.md)

View file

@ -31,6 +31,8 @@ weakest to strongest:
- `passkey`
- `attested_passkey`
`attested_passkey` requires [configuring an allowlist of trusted authenticators](#setting-webauthn-attestation-ca-lists).
### Password Minimum Length
The minimum length for passwords (if they are allowed).
@ -45,7 +47,7 @@ read/write session.
The list of certificate authorities and device aaguids that must be used by members of this policy.
This allows limiting devices to specific models.
To generate this list you should use `fido-mds-tool`.
To generate this list you should [use `fido-mds-tool`](#setting-webauthn-attestation-ca-lists).
## Policy Resolution
@ -149,15 +151,59 @@ kanidm group account-policy privilege-expiry my_admin_group 86400 # NB: will be
### Setting Webauthn Attestation CA Lists
The list should be generated with `fido-mds-tool`. This will emit JSON that can be directly used
with Kanidm.
To verify Webauthn authenticators with attestation, Kanidm needs an allowlist of
authenticators to trust. Generate this list with the `fido-mds-tool` from
the [webauthn-rs project](https://github.com/kanidm/webauthn-rs). If you have a
Rust toolchain installed, it can built and installed from source with
```bash
kanidm group account-policy webauthn-attestation-ca-list <group name> <attestation ca list json>
kanidm group account-policy webauthn-attestation-ca-list idm_all_persons '{"cas":{"D6E4b4Drh .... }'
cargo install fido-mds-tool
```
> NOTE: `fido-mds-tool` is available in the `kanidm:tools` container.
Alternatively, `fido-mds-tool` is available in the
[tools container](../installing_client_tools.md#tools-container).
First, fetch the MDS data provided by the FIDO Alliance:
```bash
fido-mds-tool fetch
```
Then, query the MDS data to generate your allowlist of authenticators.
For example, to trust all authenticators made by Yubico, run
```bash
fido-mds-tool query --output-cert-roots "desc cnt yubikey" > trusted-authenticators
```
For details of how to query the MDS data, run
```bash
fido-mds-tool query --help
```
Once you have generated the authenticator allowlist, use it to configure Kanidm's
account policy for a group. For example, to set the allowlist for all persons, run
```bash
kanidm group account-policy webauthn-attestation-ca-list idm_all_persons trusted-authenticators
```
### Setting Primary Credential Fallback
The primary credential fallback enables behavior which allows authenticating
using the primary account password when logging in via LDAP.
If both an LDAP and primary password are specified, Kanidm will only accept the LDAP password.
```bash
kanidm group account-policy allow-primary-cred-fallback <group name> <enabled>
```
to disable it for a group you would run:
```bash
kanidm group account-policy allow-primary-cred-fallback <group name> false
```
## Global Settings

View file

@ -110,9 +110,9 @@ These validity settings impact all authentication functions of the account (kani
By default, Kanidm allows an account to change some attributes, but not their mail address.
Adding the user to the `idm_people_self_write_mail` group, as shown below, allows the user to edit
Adding the user to the `idm_people_self_mail_write` group, as shown below, allows the user to edit
their own mail.
```bash
kanidm group add-members idm_people_self_write_mail demo_user --name idm_admin
kanidm group add-members idm_people_self_mail_write demo_user --name idm_admin
```

View file

@ -58,6 +58,21 @@ can only use the UID range `1879048192` (`0x70000000`) to `2147483647` (`0x7ffff
limitations of the Linux kernel and
[systemd reserving other uids in the range](http://systemd.io/UIDS-GIDS/) for its exclusive use.
| name | min | max |
|------|-----|-----|
| system | 0 | 999 |
| user | 1000 | 60000 |
| systemd homed | 60001 | 60577 |
| unused A | 60578 | 61183 |
| systemd dynuser | 61184 | 65519 |
| unused B | 65520 | 65533 |
| nobody | 65534 | 65534 |
| 16bit limit | 65535 | 65535 |
| unused C | 65536 | 524287 |
| systemd nspawn | 524288 | 1879048191 |
| kanidm dyn alloc | 1879048192 | 2147483647 |
| unusable | 2147483648 | 4294967295 |
A valid concern is the possibility of duplication in the lower 24 bits. Given the
[birthday problem](https://en.wikipedia.org/wiki/Birthday_problem), if you have ~7700 groups and
accounts, you have a 50% chance of duplication. With ~5000 you have a 25% chance, ~930 you have a 1%
@ -67,7 +82,7 @@ We advise that if you have a site with greater than approximately 2,000 users yo
external system to allocate GID numbers serially or consistently to avoid potential duplication
events.
We recommend the use of the range `65536` through `524287` for manual allocation. This leaves the
We recommend the use of the range `65536` through `524287` (`unused C`) for manual allocation. This leaves the
range `1000` through `65535` for OS/Distro purposes, and allows Kanidm to continue dynamic
allocation in the range `1879048192` to `2147483647` if you choose a hybrid allocation approach.

View file

@ -11,14 +11,15 @@ when choosing a domain.
> **Bad choices** of domain name may have security impacts on your Kanidm
> instance, not limited to credential phishing, theft, session leaks and more.
>
> **Changing** domain name is hard to do it not only means reconfiguring all
> LDAP and OAuth clients, but will also break all registered WebAuthn
> credentials for all users (which are bound to an `Origin`).
> [**Changing** domain name is hard to do](./domain_rename.md) it not only
> means reconfiguring all LDAP and OAuth clients, but will also break all
> registered WebAuthn credentials for all users (which are bound to an
> `Origin`).
>
> It's critical that you consider and follow the advice in this chapter, and
> aim to get it right the first time.
>
> You'll save yourself a lot of work later!
> You'll save yourself (and your users) a lot of work later!
<!-- -->
@ -89,7 +90,7 @@ country cease to exist (eg: [as for `.io`][dot-io]).
### Top-level domains containing "kanidm"
We ask that you **do not** use the word `kanidm` as part of your instance's
*top-level* (or [public suffix][ps]) domain, eg: `contosokanidm.example`.
*top-level* (or [public-suffix-level][ps]) domain, eg: `contoso-kanidm.example`.
Use something like `auth`, `idm`, `login` or `sso` instead they're shorter,
too!
@ -98,10 +99,10 @@ We're OK with you using `kanidm` in a *subdomain* to point to your Kanidm
instance, eg: `kanidm.example.com`.
We've worked hard to build this project, and using its name in conjunction with
an organisation *not* associated with the project dilutes the name's branding
an organisation *not* associated with the project dilutes the name's brand
value.
### Subdomains and Origin policy
### Subdomains and Cross-Origin policy
Browsers allow a server on a subdomain to use intra-domain resources, and access
and set credentials and cookies from all of its parents until a
@ -154,9 +155,80 @@ This can be an issue if Kanidm shares a domain with:
* third-party servers *outside* of your organisation's control (eg: SaaS apps)
* anything which can be deployed to with minimal oversight (eg: a web host that
allows uploading content via unencrypted FTP)
* DNS entries that resolve to arbitrary IP addresses (eg:
`192-0-2-1.ipv4.example.com` to `192.0.2.1`, and `192.0.2.1` is not under
the authority of `example.com`)
[matrix-csp]: https://github.com/element-hq/synapse/blob/develop/README.rst#security-note
In most cases, hosting Kanidm on a subdomain of a separate top-level (or
*existing* [public-suffix level][ps]) domain (eg: `idm.contoso-auth.example`) is
sufficient to isolate your Kanidm deployment's `Origin` from other applications
and services.
> [!WARNING]
>
> There is generally **no need** to request additions to
> [the public suffix list][ps] to deploy Kanidm securely,
> *even for multi-environment deployments*.
>
> The **only** exception is to *remove* an *existing* opt-out that affects your
> domain where it must operate under a particular suffix (eg: a NSW government
> agency using `example.nsw.gov.au`).
>
> Such requests are a
> [major burden for the *volunteer-operated* list][ps-diffusion], can take
> [months to roll out to clients][ps-rollout], and changes may have unintended
> side-effects.
>
> By comparison, registering a separate domain is easy, and takes minutes.
[ps-diffusion]: https://github.com/publicsuffix/list/wiki/Third-Party-Diffusion
[ps-rollout]: https://github.com/publicsuffix/list/wiki/Guidelines#appropriate-expectations-on-derivative-propagation-use-or-inclusion
> [!TIP]
>
> Web apps (and APIs) that authenticate with
> [OAuth 2.0/OpenID Connect](./integrations/oauth2.md) **never** need to share
> cookies or Origin with Kanidm, so they **do not** need to be on the same
> top-level (or [public-suffix-level][ps]) domain.
>
> Large public auth providers (eg: Google, Meta, Microsoft) work the same way
> with both first and third-party web apps.
### Kanidm requires its own hostname
Kanidm must be the *only* thing running on a hostname, served from `/`, with all
its paths served as-is.
It cannot:
* be run from a subdirectory (eg: `https://example.com/kanidm/`)
* have *other* services accessible on the hostname in subdirectories (eg:
`https://idm.example.com/wiki/`)
* have *other* services accessible over HTTP or HTTPS at the same hostname on a
different port (eg: `https://idm.example.com:8080/`)
These introduce similar security risks to the
[subdomain issues described above](#subdomains-and-cross-origin-policy).
One reasonable exception is to serve [ACME HTTP-01 challenges][acme-http] (for
Let's Encrypt) at `http://${hostname}/.well-known/acme-challenge/`. You'll need
a *separate* HTTP server to respond to these challenges, and ensure that only
authorised processes can request a certificate for Kanidm's hostname.
[acme-http]: https://letsencrypt.org/docs/challenge-types/#http-01-challenge
> [!TIP]
>
> The `/.well-known/` path ([RFC 8615][]) can be assigned security-sensitive
> meaning in other protocols, similar to [ACME HTTP-01][acme-http].
>
> Kanidm currently uses this path for OpenID Connect Discovery, and may use it
> for other integrations in the future.
[RFC 8615]: https://datatracker.ietf.org/doc/html/rfc8615
### Avoid wildcard and widely-scoped certificates
CAs can issue wildcard TLS certificates, which apply to all subdomains in the
@ -212,18 +284,12 @@ For **maximum** security, your Kanidm domain name should be a subdomain of a
top-level domain (or domain under a [public suffix][ps]) that has no other
services assigned it, eg:
* Origin: `https://idm.exampleauth.example`
* Domain name: `idm.exampleauth.example`
* Origin: `https://idm.example-auth.example`
* Domain name: `idm.example-auth.example`
When using [OAuth 2.0/OpenID Connect](./integrations/oauth2.md), there is no
need for a client app to share a top-level domain with Kanidm, because the app
does not need to share cookies.
Large public auth providers (eg: Google, Meta, Microsoft) work the same way with
both first and third-party apps.
If you have strict security controls for all apps on your top-level domain, you
could run Kanidm on a subdomain of your main domain, eg:
If you have
[strict security controls for all apps on your top-level domain](#subdomains-and-cross-origin-policy),
you could run Kanidm on a subdomain of your main domain, eg:
* Origin: `https://idm.example.com`
* Domain name: `idm.example.com`
@ -233,8 +299,9 @@ restrict changes that *could* affect your IDM infrastructure.
> [!NOTE]
>
> This is the **inverse** of the common Active Directory practice of using the
> organisation's primary top-level domain directly, eg: `example.com`.
> Using a subdomain is the **inverse** of the common Active Directory practice
> of using the organisation's primary top-level domain directly, eg:
> `example.com`.
### Multi-environment and regional deployments

55
book/src/customising.md Normal file
View file

@ -0,0 +1,55 @@
# Customising
> [!NOTE]
>
> Currently theming options such as updating the CSS requires modifying the style.css file. This
> may be changed in the future to make it easier to modify.
Kanidm supports customising various aspects such as the site display name, site image, and display
names and images for each application.
## Changing the site
### Updating the display Name
By default, the display name is 'Kanidm <hostname>' which is visible when logged in. To modify the
display name, run the following
```bash
kanidm system domain set-displayname <new-display-name> -D admin
```
### Updating the site image
Similarly instead of the default Ferris the crab logo, the image on the signin page can be updated
or reset with the below commands. The image must satisfy the following conditions:
1. Maximum 1024 x 1024 pixels
2. Less than 256 KB
3. Is a supported image file type: png, jpg, gif, svg, webp
```bash
kanidm system domain set-image <file-path> [image-type] -D admin
kanidm system domain remove-image -D admin
```
## Changing a resource server
### Updating the display name
Each application can have its display name updated with the following
```bash
kanidm system oauth2 set-displayname <NAME> <displayname> -D idm_admin
```
### Updating the image
Each application can have its image updated or reset with the following commands. The image is
subject to the same restrictions as the site image above.
```bash
kanidm system oauth2 set-image <NAME> <file-path> [image-type] -D idm_admin
kanidm system oauth2 remove-image <NAME> -D idm_admin
```

View file

@ -7,10 +7,10 @@ support machine accounts also know as domain joining.
### Limiting Unix Password Auth
Currently unix password authentication is targetted as the method for sudo. Initial access to the
Currently unix password authentication is targeted as the method for sudo. Initial access to the
machine should come from ssh keys (and in future, ctap2).
In order to maintain compatability with LDAP style authentication, we allow "anonymous hosts" to
In order to maintain compatibility with LDAP style authentication, we allow "anonymous hosts" to
retrieve ssh public keys, and then perform sudo authentication.
This has the obvious caveat that anyone can stand up a machine that trusts a Kanidm instance. This

View file

@ -38,7 +38,7 @@ There are different ways we can scope a trust out, each with pros-cons. Here are
may implement some controls around which subject DN's to allow/deny, but this is pretty fraught
with landminds. You don't know who exists until they login!
* Azure AD individual account trusting. Instead of trusting a whole domain you allow a user from
a remote tennant to access your resources. You don't trust everyone in their tennant, just that
a remote tenant to access your resources. You don't trust everyone in their tenant, just that
one account that you can invite. You can then revoke them as needed.
* Group-trust - FreeIPA does this with AD. It's still like kerberos, but you only trust a subset
of the users determined by "groups" from the trusted site.

View file

@ -65,12 +65,12 @@ same. // TODO: Should a user be allowed to relabel their kanidm ssh keys ?
Due to their long length they should be line-wrapped into a text field so the entirety is visible
when shown. To reduce visible clutter and inconsistent spacing we will put the values into
collapsable elements.
collapsible elements.
These collapsed elements must include:
- label
- value's key type (ECDSA, rsa, ect..) and may include:
- value's key type (ECDSA, rsa, etc..) and may include:
- value's comment, truncated to some max length
#### Editing keys

View file

@ -54,7 +54,7 @@ to improve it as a result. This will necesitate a major rework of the project.
The current design treated the client as a trivial communication layer. The daemon/event loop
contained all state including if the resolver was online or offline. Additionally the TPM and
password caching operations primarily occured in the daemon layer, which limited the access of these
password caching operations primarily occurred in the daemon layer, which limited the access of these
features to the client backend itself.
### Future Features
@ -130,7 +130,7 @@ future.
#### CTAP2 / TPM-PIN
We want to allow local authentication with CTAP2 or a TPM with PIN. Both provide stronger assurances
of both who the user is, and that they are in posession of a specific cryptographic device. The nice
of both who the user is, and that they are in possession of a specific cryptographic device. The nice
part of this is that they both implement hardware bruteforce protections. For soft-tpm we can
emulate this with a strict bruteforce lockout prevention mechanism.
@ -384,7 +384,7 @@ and rely on sqlite heavily.
We should migrate to a primarily in-memory cache, where sqlite is used only for persistence. The
sqlite content should be optionally able to be encrypted by a TPM bound key.
To obsfucate details, the sqlite db should be a single table of key:value where keys are uuids
To obfuscate details, the sqlite db should be a single table of key:value where keys are uuids
associated to the item. The uuid is a local detail, not related to the provider.
The cache should move to a concread based concurrent tree which will also allow us to multi-thread

View file

@ -45,6 +45,7 @@ can take many forms such as.
- firstname firstname lastname
- firstname lastname lastname
- firstname
- middlename lastname
- lastname firstname
And many many more that are not listed here. This is why our names are displayName as a freetext

View file

@ -114,3 +114,7 @@ When a service like sudo, sshd, su, etc. wants to authenticate someone, it opens
that service, then performs authentication according to the modules defined in the pam.d config. For
example, if you run `ls -al /etc/pam.d /usr/etc/pam.d` in SUSE, you can see the services and their
respective pam.d config.
## Test coverage
We're trying to regularly get coverage reports into [Coveralls](https://coveralls.io/github/kanidm/kanidm), you can run the local testing with `make coverage` once you've installed [cargo-tarpaulin](https://crates.io/crates/cargo-tarpaulin).

View file

@ -100,21 +100,16 @@ You will need [rustup](https://rustup.rs/) to install a Rust toolchain.
### SUSE / OpenSUSE
> NOTE: clang and lld are required to build Kanidm due to performance issues with GCC/ld
You will need to install rustup and our build dependencies with:
```bash
zypper in rustup git libudev-devel sqlite3-devel libopenssl-3-devel libselinux-devel pam-devel tpm2-0-tss-devel
zypper in rustup git libudev-devel sqlite3-devel libopenssl-3-devel libselinux-devel \
pam-devel systemd-devel tpm2-0-tss-devel clang lld make sccache
```
You can then use rustup to complete the setup of the toolchain.
In some cases you may need to build other vendored components, or use an alternate linker. In these
cases we advise you to also install.
```bash
zypper in clang lld make sccache
```
You should also adjust your environment with:
```bash
@ -123,25 +118,16 @@ export CC="sccache /usr/bin/clang"
export CXX="sccache /usr/bin/clang++"
```
And add the following to a cargo config of your choice (such as ~/.cargo/config), adjusting for cpu
arch
```toml
[target.aarch64-unknown-linux-gnu]
linker = "clang"
rustflags = [
"-C", "link-arg=-fuse-ld=lld",
]
```
### Fedora
> NOTE: clang and lld are required to build Kanidm due to performance issues with GCC/ld
You will need [rustup](https://rustup.rs/) to install a Rust toolchain.
You will also need some system libraries to build this:
```text
systemd-devel sqlite-devel openssl-devel pam-devel
systemd-devel sqlite-devel openssl-devel pam-devel clang lld
```
Building the Web UI requires additional packages:
@ -152,12 +138,14 @@ perl-FindBin perl-File-Compare
### Ubuntu
> NOTE: clang and lld are required to build Kanidm due to performance issues with GCC/ld
You need [rustup](https://rustup.rs/) to install a Rust toolchain.
You will also need some system libraries to build this, which can be installed by running:
```bash
sudo apt-get install libudev-dev libssl-dev pkg-config libpam0g-dev
sudo apt-get install libudev-dev libssl-dev libsystemd-dev pkg-config libpam0g-dev clang lld
```
Tested with Ubuntu 20.04 and 22.04.

View file

@ -3,57 +3,58 @@
## Pre-Reqs
```bash
cargo install cargo-audit
cargo install cargo-outdated
cargo install cargo-udeps
cargo install --force \
cargo-audit \
cargo-outdated \
cargo-udeps \
cargo-machete
```
## Pre Release Check List
### Start a release
- [ ] git checkout -b YYYYMMDD-pre-release
- [ ] `git checkout -b "$(date +%Y%m%d)-pre-release"`
### Cargo Tasks
- [ ] Update MSRV if applicable
- [ ] cargo update
- [ ] `cargo update`
- [ ] `RUSTC_BOOTSTRAP=1 cargo udeps`
- [ ] cargo outdated -R
- [ ] cargo audit
- [ ] cargo test
- [ ] `cargo machete --with-metadata`
- [ ] `cargo outdated -R`
- [ ] `cargo audit`
- [ ] `cargo test`
- [ ] setup a local instance and run orca (TBD)
- [ ] store a copy an an example db (TBD)
### Code Changes
- [ ] upgrade crypto policy values if required
- [ ] upgrade crypto policy values if required (see `libs/crypto/src/lib.rs` -> `CryptoPolicy`)
- [ ] check for breaking db entry changes.
### Administration
- [ ] Update `RELEASE_NOTES.md`
- [ ] Update `README.md`
- [ ] cargo test
- [ ] git commit
- [ ] git push origin YYYYMMDD-pre-release
- [ ] `cargo test`
- [ ] `git commit -a -m 'chore: Release Notes'`
- [ ] `git push origin "$(date +%Y%m%d)-pre-release"`
- [ ] Merge PR
### Git Management
- [ ] git checkout master
- [ ] git pull
- [ ] git checkout -b 1.1.x (Note no v to prevent ref conflict)
- [ ] `git checkout master`
- [ ] `git pull`
- [ ] git checkout -b 1.x.0 (Note no v to prevent ref conflict)
- [ ] update version to set pre tag in ./Cargo.toml
- [ ] update version to set pre tag in ./Makefile
- [ ] git commit
- [ ] git tag v1.1.x-pre
- [ ] `git commit -m "Release $(cargo metadata --format-version 1 | jq '.packages[] | select(.name=="kanidm_proto") | .version')-pre"`
- [ ] `git tag v$(cargo metadata --format-version 1 | jq '.packages[] | select(.name=="kanidm_proto") | .version')-pre`
- [ ] Final inspect of the branch
- [ ] git push origin 1.1.x
- [ ] git push origin 1.1.x --tags
- [ ] `git push origin "$(cargo metadata --format-version 1 | jq '.packages[] | select(.name=="kanidm_proto") | .version')" --tags`
- [ ] github -> Ensure release branch is protected
@ -63,20 +64,21 @@ cargo install cargo-udeps
- [ ] git pull
- [ ] git checkout -b YYYYMMDD-dev-version
- [ ] update version to +1 and add dev tag in ./Cargo.toml
- [ ] update version to +1 and add dev tag in ./Makefile
- [ ] update `DOMAIN_*_LEVEL` in server/lib/src/constants/mod.rs
- [ ] update and add new migrations
## Final Release Check List
### Git Management Part Deux
- [ ] git checkout 1.1.x
- [ ] git pull origin 1.1.x
- [ ] git checkout 1.x.0
- [ ] git pull origin 1.x.0
- [ ] update version to remove pre tag in ./Cargo.toml
- [ ] update version to remove pre tag in ./Makefile
- [ ] git tag v1.1.x
- [ ] git push origin 1.1.x --tags
- [ ] update Makefile to set docker image to latest
- [ ] git commit -a -m 'Release 1.x.0'
- [ ] git tag v1.x.0
- [ ] git push origin 1.x.0 --tags
- [ ] github -> create new release based on tag (not branch) - use tag because then tools will get
the tag + patches we apply.
@ -99,8 +101,7 @@ cargo install cargo-udeps
### Docker
- [ ] docker buildx use cluster
- [ ] `make buildx/kanidmd/x86_64_v3 buildx/kanidmd buildx/kanidm_tools buildx/radiusd`
- [ ] `IMAGE_VERSION=latest make buildx`
- [ ] `make buildx`
- [ ] Update the readme on docker <https://hub.docker.com/repository/docker/kanidm/server>
### Distro

View file

@ -54,7 +54,6 @@ services:
- traefik.http.routers.kanidm.entrypoints=websecure
- traefik.http.routers.kanidm.rule=Host(`idm.example.com`)
- traefik.http.routers.kanidm.service=kanidm
- traefik.http.serversTransports.kanidm.insecureSkipVerify=true
- traefik.http.services.kanidm.loadbalancer.server.port=8443
- traefik.http.services.kanidm.loadbalancer.server.scheme=https
volumes:

View file

@ -75,7 +75,7 @@ administrator. While they may not have direct access to the client/application s
still use this `client_id+secret` to then carry out the authorisation code interception attack
listed.
For confidential clients (refered to as a `basic` client in Kanidm due to the use of HTTP Basic for
For confidential clients (referred to as a `basic` client in Kanidm due to the use of HTTP Basic for
`client_id+secret` presentation) PKCE may optionally be disabled. This can allow authorisation code
attacks to be carried out - however _if_ TLS is used and the `client_secret` never leaks, then these
attacks will not be possible. Since there are many public references to system administrators

View file

@ -137,9 +137,9 @@ chmod 666 ~/.cache/kanidm_tokens
docker pull kanidm/tools:latest
docker run --rm -i -t \
--network host \
--mount "type=bind,src=/etc/kanidm/config,target=/etc/kanidm/config" \
--mount "type=bind,src=$HOME/.config/kanidm,target=/home/kanidm/.config/kanidm" \
--mount "type=bind,src=$HOME/.cache/kanidm_tokens,target=/home/kanidm/.cache/kanidm_tokens" \
--mount "type=bind,src=/etc/kanidm/config,target=/data/config:ro" \
--mount "type=bind,src=$HOME/.config/kanidm,target=/root/.config/kanidm" \
--mount "type=bind,src=$HOME/.cache/kanidm_tokens,target=/root/.cache/kanidm_tokens" \
kanidm/tools:latest \
/sbin/kanidm --help
```

View file

@ -145,7 +145,8 @@ with a dn of `dn=token` and provide the api token in the password.
> [!NOTE]
>
> The `dn=token` keyword is guaranteed to not be used by any other entry, which is why it was chosen
> as the keyword to initiate api token binds.
> as the keyword to initiate api token binds. Additionally it is not required, leaving the field empty
> will fall back to the service-account if a "password" is provided
```bash
ldapwhoami -H ldaps://URL -x -D "dn=token" -w "TOKEN"
@ -234,6 +235,7 @@ ldapwhoami ... -x -D '22a65b6c-80c8-4e1a-9b76-3f3afdff8400'
ldapwhoami ... -x -D 'spn=test1@idm.example.com,dc=idm,dc=example,dc=com'
ldapwhoami ... -x -D 'name=test1,dc=idm,dc=example,dc=com'
```
<sub>in fact, the key of the bind isn't used at all so `googoogaaga=test1` is entirely valid</sub> ;)
## Troubleshooting

View file

@ -45,6 +45,7 @@ introspection.
Kanidm will expose its OAuth2 APIs at the following URLs, substituting
`:client_id:` with an OAuth2 client ID.
<!-- markdownlint-disable MD033 -->
<dl>
@ -59,7 +60,7 @@ URL **(recommended)**
`https://idm.example.com/oauth2/openid/:client_id:/.well-known/openid-configuration`
This document includes all the URLs and attributes an app needs to be able to
authenticate using OIDC with Kanidm, *except* for the `client_id` and
authenticate using OIDC with Kanidm, _except_ for the `client_id` and
`client_secret`.
Use this document wherever possible, as it will allow you to easily build and/or
@ -69,11 +70,10 @@ anything special for Kanidm (or another provider).
**Note:** some apps automatically append `/.well-known/openid-configuration` to
the end of an OIDC Discovery URL, so you may need to omit that.
</dd>
<dt>
[RFC 8414 OAuth 2.0 Authorisation Server Metadata](https://datatracker.ietf.org/doc/html/rfc8414) URL
[RFC 8414 OAuth 2.0 Authorisation Server Metadata](https://datatracker.ietf.org/doc/html/rfc8414)
URL **(recommended)**
</dt>
@ -85,6 +85,21 @@ the end of an OIDC Discovery URL, so you may need to omit that.
<dt>
[WebFinger URL](#webfinger) **(discouraged)**
</dt>
<dd>
`https://idm.example.com/oauth2/openid/:client_id:/.well-known/webfinger`
See [the WebFinger section](#webfinger) for more details, as there a number of
caveats for WebFinger clients.
</dd>
<dt>
User auth
</dt>
@ -147,7 +162,7 @@ Token endpoint
<dt>
OpenID Connect issuer URI
OpenID Connect Issuer URL
</dt>
@ -183,11 +198,13 @@ Token signing public key
</dl>
<!-- markdownlint-enable MD037 -->
## Configuration
### Create the Kanidm Configuration
By default, members of the `system_admins` or `idm_hp_oauth2_manage_priv` groups are able to create
By default, members of the `idm_admins` or `idm_oauth2_admins` groups are able to create
or manage OAuth2 client integrations.
You can create a new client by specifying its client name, application display name and the landing
@ -210,7 +227,7 @@ You can create a scope map with:
```bash
kanidm system oauth2 update-scope-map <name> <kanidm_group_name> [scopes]...
kanidm system oauth2 update-scope-map nextcloud nextcloud_admins admin
kanidm system oauth2 update-scope-map nextcloud nextcloud_users email profile openid
```
> [!TIP]
@ -220,18 +237,27 @@ kanidm system oauth2 update-scope-map nextcloud nextcloud_admins admin
> claims may be added to the authorisation token. It is not guaranteed that all of the associated
> claims will be added.
>
> - **profile** - name, family_name, given_name, middle_name, nickname, preferred_username, profile,
> * **profile** - name, family_name, given_name, middle_name, nickname, preferred_username, profile,
> picture, website, gender, birthdate, zoneinfo, locale, and updated_at
> - **email** - email, email_verified
> - **address** - address
> - **phone** - phone_number, phone_number_verified
> * **email** - email, email_verified
> * **address** - address
> * **phone** - phone_number, phone_number_verified
> * **groups** - groups
>
> In addition Kanidm supports some vendor specific scopes that can include additional claims.
>
> * **ssh_publickeys** - array of ssh_publickey of the user
<!-- this is just to split the templates up -->
> [!WARNING]
>
> If you are creating an OpenID Connect (OIDC) client you **MUST** provide a scope map named
> If you are creating an OpenID Connect (OIDC) client you **MUST** provide a scope map containing
> `openid`. Without this, OpenID Connect clients **WILL NOT WORK**!
>
> ```bash
> kanidm system oauth2 update-scope-map nextcloud nextcloud_users openid
> ```
You can create a supplemental scope map with:
@ -311,10 +337,7 @@ applications that act as the OAuth2 client and its corresponding webserver is th
In this case, the SPA is unable to act as a confidential client since the basic secret would need to
be embedded in every client.
Another common example is native applications that use a redirect to localhost. These can't have a
client secret embedded, so must act as public clients.
Public clients for this reason require PKCE to bind a specific browser session to its OAuth2
For this reason, public clients require PKCE to bind a specific browser session to its OAuth2
exchange. PKCE can not be disabled for public clients for this reason.
To create an OAuth2 public client:
@ -324,7 +347,13 @@ kanidm system oauth2 create-public <name> <displayname> <origin>
kanidm system oauth2 create-public mywebapp "My Web App" https://webapp.example.com
```
To allow localhost redirection
## Native Applications
Some applications will run a local web server on the user's device which directs users to the IDP for
authentication, then back to the local server. [BCP212](https://www.rfc-editor.org/info/bcp212)
"OAuth 2.0 for Native Apps" specifies the rules for this.
First allow localhost redirects:
```bash
kanidm system oauth2 enable-localhost-redirects <name>
@ -332,6 +361,10 @@ kanidm system oauth2 disable-localhost-redirects <name>
kanidm system oauth2 enable-localhost-redirects mywebapp
```
> [!WARNING]
>
> Kanidm only allows these to be enabled on public clients where PKCE is enforced.
## Alternate Redirect URLs
> [!WARNING]
@ -374,8 +407,10 @@ To indicate your readiness for this transition, all OAuth2 clients must have the
`strict-redirect-url` enabled. Once enabled, the client will begin to enforce the 1.4.0 strict
validation behaviour.
If you have not enabled `strict-redirect-url` on all OAuth2 clients the upgrade to 1.4.0 will refuse
to proceed.
> [!WARNING]
>
> If you have not enabled `strict-redirect-url` on all OAuth2 clients the upgrade to 1.4.0 will refuse
> to proceed.
To enable or disable strict validation:
@ -420,3 +455,86 @@ kanidm system oauth2 reset-secrets
```
Each client has unique signing keys and access secrets, so this is limited to each service.
## WebFinger
[WebFinger][webfinger] provides a mechanism for discovering information about
entities at a well-known URL (`https://{hostname}/.well-known/webfinger`).
It can be used by a WebFinger client to
[discover the OIDC Issuer URL][webfinger-oidc] of an identity provider from the
hostname alone, and seems to be intended to support dynamic client registration
flows for large public identity providers.
Kanidm v1.5.1 and later can respond to WebFinger requests, using a user's SPN as
part of [an `acct` URI][rfc7565] (eg: `acct:user@idm.example.com`). While SPNs
and `acct` URIs look like email addresses, [as per RFC 7565][rfc7565s4], there
is no guarantee that it is valid for any particular application protocol, unless
an administrator explicitly provides for it.
When setting up an application to authenticate with Kanidm, WebFinger **does not
add any security** over configuring an OIDC Discovery URL directly. In an OIDC
context, the specification makes a number of flawed assumptions which make it
difficult to use with Kanidm:
* WebFinger assumes that an identity provider will use the same Issuer URL and
OIDC Discovery document (which contains endpoint URLs and token signing keys)
for *all* OAuth 2.0/OIDC clients.
Kanidm uses *client-specific* Issuer URLs, endpoint URLs and token signing
keys. This ensures that tokens can only be used with their intended service.
* WebFinger endpoints must be served at the *root* of the domain of a user's
SPN (ie: information about the user with SPN `user@idm.example.com` is at
`https://idm.example.com/.well-known/webfinger?resource=acct%3Auser%40idm.example.com`).
Unlike OIDC Discovery, WebFinger clients do not report their OAuth 2.0/OIDC
client ID in the request, so there is no way to tell them apart.
As a result, Kanidm *does not* provide a WebFinger endpoint at its root URL,
because it could report an incorrect Issuer URL and lead the client to an
incorrect OIDC Discovery document.
You will need a load balancer in front of Kanidm's HTTPS server to send a HTTP
307 redirect to the appropriate
`/oauth2/openid/:client_id:/.well-known/webfinger` URL, *while preserving all
query parameters*. For example, with Caddy:
```caddy
# Match on a prefix, and use {uri} to preserve all query parameters.
# This only supports *one* client.
example.com {
redir /.well-known/webfinger https://idm.example.com/oauth2/openid/:client_id:{uri} 307
}
```
If you have *multiple* WebFinger clients, it will need to map some other
property of the request (such as a source IP address or `User-Agent` header)
to a client ID, and redirect to the appropriate WebFinger URL for that client.
* Kanidm responds to *all* WebFinger queries with
[an Identity Provider Discovery for OIDC URL][webfinger-oidc], **ignoring**
[`rel` parameter(s)][webfinger-rel].
If you want to use WebFinger in any *other* context on Kanidm's hostname,
you'll need a load balancer in front of Kanidm which matches on some property
of the request.
WebFinger clients *may* omit the `rel=` parameter, so if you host another
service with relations for a Kanidm [`acct:` entity][rfc7565s4] and a client
*does not* supply the `rel=` parameter, your load balancer will need to merge
JSON responses from Kanidm and the other service(s).
Because of these issues, we recommend that applications support *directly*
configuring OIDC using a Discovery URL or OAuth 2.0 Authorisation Server
Metadata URL instead of WebFinger.
If a WebFinger client only checks WebFinger once during setup, you may wish to
temporarily serve an appropriate static WebFinger document for that client
instead.
[rfc7565]: https://datatracker.ietf.org/doc/html/rfc7565
[rfc7565s4]: https://datatracker.ietf.org/doc/html/rfc7565#section-4
[webfinger]: https://datatracker.ietf.org/doc/html/rfc7033
[webfinger-oidc]: https://datatracker.ietf.org/doc/html/rfc7033#section-3.1
[webfinger-rel]: https://datatracker.ietf.org/doc/html/rfc7033#section-4.3

View file

@ -1,5 +1,9 @@
# Example OAuth2 Configurations
> [!TIP]
>
> Web applications that authenticate with Kanidm **must** be served over HTTPS.
## Apache `mod_auth_openidc`
Add the following to a `mod_auth_openidc.conf`. It should be included in a `mods_enabled` folder or
@ -50,6 +54,99 @@ In the virtual host, to protect a location/directory
</Directory>
```
## Gitea
[Gitea](https://docs.gitea.com/) is a painless, self-hosted, all-in-one software
development service. It has built in support for
[external authentication](https://docs.gitea.com/administration/authentication)
including OAuth2.
To set up a Gitea instance to authenticate with Kanidm:
1. Add an email address to your regular Kanidm account, if it doesn't have one
already:
```sh
kanidm person update your_username -m your_username@example.com
```
2. Create a new Kanidm group for your Gitea users (`gitea_users`), and add your
regular account to it:
```sh
kanidm group create gitea_users
kanidm group add-members gitea_users your_username
```
3. Create a new OAuth2 application configuration in Kanidm (`gitea`), configure
the redirect URL, and scope access to the `gitea_users` group:
```sh
kanidm system oauth2 create gitea Gitea https://gitea.example.com/user/login
kanidm system oauth2 add-redirect-url gitea https://gitea.example.com/user/oauth2/kanidm/callback
kanidm system oauth2 update-scope-map gitea gitea_users email openid profile groups
```
4. Gitea currently [does not support PKCE](https://github.com/go-gitea/gitea/issues/21376)
in their OIDC implementation. If you do not perform this step, you will see an error like
`No PKCE code challenge was provided with client in enforced PKCE mode.`
in your Kanidm server logs. Therefore, we have to disable PKCE for Gitea:
```sh
kanidm system oauth2 warning-insecure-client-disable-pkce gitea
```
5. Get the `gitea` OAuth2 client secret from Kanidm:
```sh
kanidm system oauth2 show-basic-secret gitea
```
6. Log in to Gitea with an administrator account and go to Site Administration
-> Identity & Access -> Authentication Sources, and "Add Authentication Source",
then provide the following details:
* **Type**: `OAuth2`
* **Name**: `kanidm`, in case you want to choose a different name, make sure
to update `kanidm` in the redirect URL in step 3. The full redirect URL is
provided at the bottom of the current configuration page in Gitea.
* **OAuth2 Provider**: `OpenID Connect`
* **Client ID (key)**: `gitea`
* **Client Secret**: [from show-basic-secret above]
* **OpenID Connect Auto Discovery URL**: `https://kanidm.example.com/oauth2/openid/gitea/.well-known/openid-configuration`
Alternatively, you can provide the configuration via the CLI:
```sh
gitea admin auth add-oauth \
--provider=openidConnect \
--name=kanidm \
--key=gitea \
--secret=[from show-basic-secret above] \
--auto-discover-url=https://kanidm.example.com/oauth2/openid/gitea/.well-known/openid-configuration \
```
You should now see a "Sign in with Kanidm" button on your Gitea login page.
You may additionally want to configure:
* A Gitea themed icon in Kanidm for the `gitea` OAuth2 application:
```sh
curl -LO https://gitea.example.com/assets/img/logo.svg
kanidm system oauth2 set-image gitea logo.svg svg
rm logo.svg
```
* To disable password authentication in Gitea, add the following
[configuration](https://docs.gitea.com/next/administration/config-cheat-sheet)
to `app.ini`:
```ini
[service]
ALLOW_ONLY_EXTERNAL_REGISTRATION = true
SHOW_REGISTRATION_BUTTON = false
ENABLE_PASSWORD_SIGNIN_FORM = false
```
## GitLab
[GitLab](https://gitlab.com) is a Git-based software development platform, which
@ -261,7 +358,7 @@ using OAuth2:
<dd>
Upload a Kanidm or other organisational logo.
This will appear on the login form (with no text) to prompt users to sign
in.
@ -459,6 +556,65 @@ php occ config:app:set --value=0 user_oidc allow_multiple_user_backends
You can login directly by appending `?direct=1` to your login page. You can re-enable other backends
by setting the value to `1`
## OAuth2 Proxy
OAuth2 Proxy is a reverse proxy that provides authentication with OpenID Connect identity providers.
It is typically used to secure web applications without native OpenID Connect support.
Prepare the environment.
Due to a [lack of public client support](https://github.com/oauth2-proxy/oauth2-proxy/issues/1714) we have to set it up as a basic client.
```bash
kanidm system oauth2 create webapp 'webapp.example.com' 'https://webapp.example.com'
kanidm system oauth2 add-redirect-url webapp 'https://webapp.example.com/oauth2/callback'
kanidm system oauth2 update-scope-map webapp email openid
kanidm system oauth2 get webapp
kanidm system oauth2 show-basic-secret webapp
<SECRET>
```
Create a user group.
```bash
kanidm group create 'webapp_admin'
```
Setup the claim-map to add `webapp_group` to the userinfo claim.
```bash
kanidm system oauth2 update-claim-map-join 'webapp' 'webapp_group' array
kanidm system oauth2 update-claim-map 'webapp' 'webapp_group' 'webapp_admin' 'webapp_admin'
```
Authorize users for the application.
Additionally OAuth2 Proxy requires all users have an email, reference this issue for more details:
- <https://github.com/oauth2-proxy/oauth2-proxy/issues/2667>
```bash
kanidm person update '<user>' --legalname 'Personal Name' --mail 'user@example.com'
kanidm group add-members 'webapp_admin' '<user>'
```
And add the following to your OAuth2 Proxy config.
```toml
provider = "oidc"
scope = "openid email"
# change to match your kanidm domain and client id
oidc_issuer_url = "https://idm.example.com/oauth2/openid/webapp"
# client ID from `kanidm system oauth2 create`
client_id = "webapp"
# redirect URL from `kanidm system add-redirect-url webapp`
redirect_url = "https://webapp.example.com/oauth2/callback"
# claim name from `kanidm system oauth2 update-claim-map-join`
oidc_groups_claim = "webapp_group"
# user group from `kanidm group create`
allowed_groups = ["webapp_admin"]
# secret from `kanidm system oauth2 show-basic-secret webapp`
client_secret = "<SECRET>"
```
## Outline
> These instructions were tested with self-hosted Outline 0.80.2.
@ -480,7 +636,7 @@ with some limitations:
It will set the user's preferred name on *first* log in *only*.
To set up a *new* self-hosted Outline instance to authenicate with Kanidm:
To set up a *new* self-hosted Outline instance to authenticate with Kanidm:
1. Add an email address to your regular Kanidm account, if it doesn't have one
already:
@ -651,7 +807,22 @@ To set up an ownCloud instance to authenticate with Kanidm:
kanidm system oauth2 show-basic-secret owncloud
```
7. Create a JSON configuration file (`oidc-config.json`) for ownCloud's OIDC
7. Set [ownCloud's session cookie `SameSite` value to `Lax`][owncloud-samesite]:
* For manual installations, add the option
`'http.cookie.samesite' => 'Lax',` to `config.php`.
* For Docker installations, set the `OWNCLOUD_HTTP_COOKIE_SAMESITE`
environment variable to `Lax`, then stop and start the container.
When ownCloud and Kanidm are on different top-level domains
([as we recommend](../../choosing_a_domain_name.md#subdomains-and-cross-origin-policy)),
ownCloud's default `SameSite=Strict` session cookie policy causes browsers
to drop the session cookie when Kanidm redirects back to ownCloud, which
then causes their OIDC library to
[send an invalid token request to Kanidm][owncloud-session-bug], which
Kanidm (correctly) rejects.
8. Create a JSON configuration file (`oidc-config.json`) for ownCloud's OIDC
App.
To key users by UID (most secure configuration, but not suitable if you have
@ -687,7 +858,7 @@ To set up an ownCloud instance to authenticate with Kanidm:
}
```
8. Deploy the config file you created with [`occ`][occ].
9. Deploy the config file you created with [`occ`][occ].
[The exact command varies][occ] depending on how you've deployed ownCloud.
@ -726,7 +897,9 @@ login form, which you can use to sign in.
[owncloud-branding]: https://doc.owncloud.com/server/next/admin_manual/enterprise/clients/creating_branded_apps.html
[owncloud-oidcsd]: https://doc.owncloud.com/server/next/admin_manual/configuration/user/oidc/oidc.html#set-up-service-discovery
[owncloud-samesite]: https://doc.owncloud.com/server/next/admin_manual/configuration/server/config_sample_php_parameters.html#define-how-to-relax-same-site-cookie-settings
[owncloud-secrets]: https://doc.owncloud.com/server/next/admin_manual/configuration/user/oidc/oidc.html#client-ids-secrets-and-redirect-uris
[owncloud-session-bug]: https://github.com/jumbojett/OpenID-Connect-PHP/issues/453
[owncloud-oauth2-app]: https://marketplace.owncloud.com/apps/oauth2
[owncloud-ios-mdm]: https://doc.owncloud.com/ios-app/12.2/appendices/mdm.html#oauth2-based-authentication
[occ]: https://doc.owncloud.com/server/next/admin_manual/configuration/server/occ_command.html
@ -778,6 +951,7 @@ Prepare the environment:
```bash
kanidm system oauth2 create grafana "grafana.domain.name" https://grafana.domain.name
kanidm system oauth2 set-landing-url grafana 'https://grafana.domain.name/login/generic_oauth'
kanidm system oauth2 update-scope-map grafana grafana_users email openid profile groups
kanidm system oauth2 enable-pkce grafana
kanidm system oauth2 get grafana

View file

@ -97,88 +97,32 @@ kanidm group add-members --name admin idm_radius_servers radius_service_account
Now reset the account password, using the `admin` account:
```bash
kanidm service-account credential generate --name admin radius_service_account
kanidm service-account api-token generate --name admin radius_service_account
```
## Deploying a RADIUS Container
We provide a RADIUS container that has all the needed integrations. This container requires some
cryptographic material, with the following files being in `/etc/raddb/certs`. (Modifiable in the
cryptographic material, with the following files mounted in `/data`. (Modifiable in the
configuration)
| filename | description |
| -------- | ------------------------------------------------------------- |
| ca.pem | The signing CA of the RADIUS certificate |
| dh.pem | The output of `openssl dhparam -in ca.pem -out ./dh.pem 2048` |
| cert.pem | The certificate for the RADIUS server |
| key.pem | The signing key for the RADIUS certificate |
| filename | description |
| -------- | ------------------------------------------------------------- |
| ca.pem | The signing CA of the RADIUS certificate |
| cert.pem | The certificate for the RADIUS server |
| key.pem | The private key for the RADIUS certificate |
| radius.toml | The configuration file |
The configuration file (`/data/kanidm`) has the following template:
The configuration file (which you should mount at `/data/radius.toml`, or specify its path with the environment variable `KANIDM_RLM_CONFIG`) has the following template:
```toml
uri = "https://example.com" # URL to the Kanidm server
verify_hostnames = true # verify the hostname of the Kanidm server
verify_ca = false # Strict CA verification
ca = /data/ca.pem # Path to the kanidm ca
auth_token = "ABC..." # Auth token for the service account
# See: kanidm service-account api-token generate
# Default vlans for groups that don't specify one.
radius_default_vlan = 1
# A list of Kanidm groups which must be a member
# before they can authenticate via RADIUS.
radius_required_groups = [
"radius_access_allowed@idm.example.com",
]
# A mapping between Kanidm groups and VLANS
radius_groups = [
{ spn = "radius_access_allowed@idm.example.com", vlan = 10 },
]
# A mapping of clients and their authentication tokens
radius_clients = [
{ name = "test", ipaddr = "127.0.0.1", secret = "testing123" },
{ name = "docker" , ipaddr = "172.17.0.0/16", secret = "testing123" },
]
# radius_cert_path = "/etc/raddb/certs/cert.pem"
# the signing key for radius TLS
# radius_key_path = "/etc/raddb/certs/key.pem"
# the diffie-hellman output
# radius_dh_path = "/etc/raddb/certs/dh.pem"
# the CA certificate
# radius_ca_path = "/etc/raddb/certs/ca.pem"
{{#rustdoc_include ../../../examples/radius.toml}}
```
## A fully configured example
```toml
url = "https://example.com"
# The auth token for the service account
auth_token = "ABC..."
# default vlan for groups that don't specify one.
radius_default_vlan = 99
# if the user is in one of these Kanidm groups,
# then they're allowed to authenticate
radius_required_groups = [
"radius_access_allowed@idm.example.com",
]
radius_groups = [
{ spn = "radius_access_allowed@idm.example.com", vlan = 10 }
]
radius_clients = [
{ name = "localhost", ipaddr = "127.0.0.1", secret = "testing123" },
{ name = "docker" , ipaddr = "172.17.0.0/16", secret = "testing123" },
]
{{#rustdoc_include ../../../examples/radius_full.toml}}
```
## Moving to Production
@ -200,14 +144,17 @@ the problem. To increase the logging level you can re-run your environment with
```bash
docker rm radiusd
docker run --name radiusd \
-e DEBUG=True \
--rm -e DEBUG=True \
-p 1812:1812 \
-p 1812:1812/udp
-p 1812:1812/udp \
--interactive --tty \
--volume /tmp/kanidm:/etc/raddb/certs \
--mount "type=bind,src=$(pwd)/examples/radius.toml,target=/data/kanidm" \
--mount "type=bind,src=/tmp/kanidm,target=/data" \
kanidm/radius:latest
```
In this example we're running it from the root of the repository and loading an example config, and using the certificates generated in dev-mode. You'll need to adjust your mounts to suit!
Note: the RADIUS container _is_ configured to provide
[Tunnel-Private-Group-ID](https://freeradius.org/rfc/rfc2868.html#Tunnel-Private-Group-ID), so if
you wish to use Wi-Fi-assigned VLANs on your infrastructure, you can assign these by groups in the

View file

@ -5,57 +5,45 @@
- Debian packaging is complex enough that it lives in a separate repository:
[kanidm/kanidm_ppa_automation](https://github.com/kanidm/kanidm_ppa_automation).
- While official packages are available at https://kanidm.github.io/kanidm_ppa/ these instructions will guide you
through replicating the same process locally, using [cross](https://github.com/cross-rs/cross) & Docker to isolate the build process
from your normal computer and allow building packages for multiple architectures.
through replicating the same process locally, using Docker to isolate the build process from your normal computer.
- Due to the complexity of crosscompilation, we no longer support it and recommend building natively,
i.e. on the platform you're targeting.
- While the examples below will use `aarch64-unknown-linux-gnu` aka `arm64`,
the same process works for `x86_64-unknown-linux-gnu` aka `amd64` as well.
1. Start in the root directory of the main [kanidm/kanidm](https://github.com/kanidm/kanidm) repository.
1. Install cross:
```shell
cargo install cross
```
1. Pull in the separate deb packaging submodule:
```shell
git submodule update platform/debian/kanidm_ppa_automation
```
1. Launch your desired crossbuild target. Do note the script assumes you use rustup!
```shell
# See valid targets:
platform/debian/kanidm_ppa_automation/scripts/crossbuild.sh
# Launch a target:
platform/debian/kanidm_ppa_automation/scripts/crossbuild.sh debian-12-aarch64-unknown-linux-gnu
# You can also specify multiple targets within the same distribution:
platform/debian/kanidm_ppa_automation/scripts/crossbuild.sh debian-12-{aarch64,x86_64}-unknown-linux-gnu
```
1. Go get a drink of your choice while the build completes.
1. Create a sacrificial deb builder container to avoid changing your own system:
```shell
docker run --rm -it -e CI=true \
docker run --rm -it -e VERBOSE=true -e CI=true \
--mount "type=bind,src=$PWD,target=/src" \
--workdir /src \
rust:bookworm
```
1. In the container install dependencies with:
```shell
# The parameter given is which additional target debian architecture to enable (amd64, arm64, etc.)
# If your native platform is amd64, running with arm64 is enough to cover both archs.
platform/debian/kanidm_ppa_automation/scripts/install_ci_build_dependencies.sh arm64
platform/debian/kanidm_ppa_automation/scripts/install_ci_build_dependencies.sh
```
1. In the container launch the deb build:
1. Launch your desired target build:
```shell
platform/debian/kanidm_ppa_automation/scripts/build_native.sh aarch64-unknown-linux-gnu
```
1. Go get a drink of your choice while the build completes.
1. Launch the deb build:
```shell
platform/debian/kanidm_ppa_automation/scripts/build_debs.sh aarch64-unknown-linux-gnu
# Again, multiple targets also work:
platform/debian/kanidm_ppa_automation/scripts/build_debs.sh {aarch64,x86_64}-unknown-linux-gnu
```
1. You can now exit the container, the package paths displayed at the end under `target` will
persist.
## Adding or amending a deb package
The rough overview of steps is:
The rough overview of steps is as follows, see further down for details.
1. Add cargo-deb specific metadata to the rust package and any static assets. Submit your changes as
a PR.
2. Add build instructions to the separate packaging repo. Submit your changes as a PR.
2. Add build steps to the separate packaging repo. Submit your changes as a PR.
3. Go back to the main repo to update the packaging submodule reference to aid running manual dev
builds of the new package.
@ -72,8 +60,8 @@ an example, see `unix_integration/resolver/Cargo.toml`
### Configuration in the kanidm_ppa_automation repo
- The repo is: [kanidm/kanidm_ppa_automation](https://github.com/kanidm/kanidm_ppa_automation)
- Changes are needed if a new binary and/or package is added, or if build time dependencies change.
- Amend `scripts/crossbuild.sh` build rules to include new binaries or packages with shared
libraries. Search for the lines starting with `cross build`.
- Amend `scripts/build_native.sh` build rules to include new binaries or packages with shared
libraries.
- Add any new build time system dependencies to `scripts/install_ci_build_dependencies.sh`, be aware
of any difference in package names between Debian & Ubuntu.
- Add any new packages to `scripts/build_debs.sh`, search for the line starting with `for package in`.

View file

@ -147,8 +147,8 @@ Features or APIs may be removed with 1 release versions notice. Deprecations wil
### Python module
The python module will typically trail changes in functionality of the core Rust code, and will be
developed as we it for our own needs - please feel free to add functionality or improvements, or
The Python module will typically trail changes in functionality of the core Rust code, and has been
developed as we have needed it - please feel free to add functionality or improvements, or
[ask for them in a Github issue](http://github.com/kanidm/kanidm/issues/new/choose)!
All code changes will include full type-casting wherever possible.

View file

@ -22,6 +22,7 @@ This is a list of supported features and standards within Kanidm.
- [RFC4519 LDAP Schema](https://www.rfc-editor.org/rfc/rfc4519)
- FreeIPA User Schema
- [RFC7644 SCIM Bulk Data Import](https://www.rfc-editor.org/rfc/rfc7644)
- NOTE: SCIM is only supported for synchronisation from another IDP at this time.
# Database

View file

@ -33,7 +33,8 @@ You can find the name of your 389 Directory Server instance with:
```bash
# Run on the FreeIPA server
dsconf --list
dsctl --list
> slapd-DEV-KANIDM-COM
```
Using this you can show the current status of the retro changelog plugin to see if you need to
@ -83,6 +84,20 @@ kanidm-ipa-sync [-c /path/to/kanidm/config] -i /path/to/kanidm-ipa-sync -n
kanidm-ipa-sync -i /etc/kanidm/ipa-sync -n
```
As the sync tool is part of the tools container, you can run this with:
```bash
docker run --rm -i -t \
--user uid:gid \
-p 12345:12345 \
-v /etc/kanidm/config:/etc/kanidm/config:ro \
-v /path/to/kanidm.ca.pem:/path/to/kanidm.ca.pem:ro
-v /path/to/ipa-ca.pem:/etc/kanidm/ipa-ca.pem:ro \
-v /path/to/ipa-sync:/etc/kanidm/ipa-sync:ro \
kanidm/tools:latest \
kanidm-ipa-sync -i /etc/kanidm/ipa-sync -
```
## Running the Sync Tool Automatically
The sync tool can be run on a schedule if you configure the `schedule` parameter, and provide the
@ -96,11 +111,14 @@ kanidm-ipa-sync -i /etc/kanidm/ipa-sync --schedule
As the sync tool is part of the tools container, you can run this with:
```bash
docker create --name kanidm-ipa-sync \
docker run --name kanidm-ipa-sync \
--user uid:gid \
-p 12345:12345 \
-v /etc/kanidm/config:/etc/kanidm/config:ro \
-v /path/to/kanidm.ca.pem:/path/to/kanidm.ca.pem:ro
-v /path/to/ipa-ca.pem:/etc/kanidm/ipa-ca.pem:ro \
-v /path/to/ipa-sync:/etc/kanidm/ipa-sync:ro \
kanidm/tools:latest \
kanidm-ipa-sync -i /etc/kanidm/ipa-sync --schedule
```

View file

@ -17,8 +17,9 @@ sync_token = "eyJhb..."
# server in the IPA topology rather than via a load balancer or dns srv records. This
# is to prevent replication conflicts and issues due to how 389-ds content sync works.
ipa_uri = "ldaps://specific-server.ipa.dev.kanidm.com"
# Path to the IPA CA certificate in PEM format.
ipa_ca = "/path/to/kanidm-ipa-ca.pem"
# Path to the IPA CA certificate in PEM format. This can be found on an IPA server
# in the file `/etc/ipa/ca.crt`
ipa_ca = "/path/to/ipa-ca.pem"
# The DN of an account with content sync rights. By default cn=Directory Manager has
# this access.
ipa_sync_dn = "cn=Directory Manager"

View file

@ -1,7 +1,7 @@
## Kanidm minimal Service Configuration - /etc/kanidm/config
# For a full example and documentation, see /usr/share/kanidm/kanidm
# Kanidm minimal Service Configuration - /etc/kanidm/config
# For a full example and documentation, see /usr/share/kanidm/config
# or `example/kanidm` in the source repository.
# Replace this with your kanidmd URI and uncomment the line
#uri = "https://idm.example.com"
# uri = "https://idm.example.com"
verify_ca = true

18
examples/radius.toml Normal file
View file

@ -0,0 +1,18 @@
uri = "https://example.com"
# The auth token for the service account
auth_token = "ABC..."
# default vlan for groups that don't specify one.
radius_default_vlan = 99
# if the user is in one of these Kanidm groups,
# then they're allowed to authenticate
radius_required_groups = ["radius_access_allowed@idm.example.com"]
radius_groups = [{ spn = "radius_access_allowed@idm.example.com", vlan = 10 }]
radius_clients = [
{ name = "localhost", ipaddr = "127.0.0.1", secret = "testing123" },
{ name = "docker", ipaddr = "172.17.0.0/16", secret = "testing123" },
]

28
examples/radius_full.toml Normal file
View file

@ -0,0 +1,28 @@
uri = "https://example.com" # URL to the Kanidm server
verify_hostnames = true # verify the hostname of the Kanidm server
verify_ca = true # Strict CA verification
auth_token = "ABC..." # Auth token for the service account
# See: kanidm service-account api-token generate
# Default vlans for groups that don't specify one.
radius_default_vlan = 1
# A list of Kanidm groups which must be a member
# before they can authenticate via RADIUS.
radius_required_groups = ["radius_access_allowed@idm.example.com"]
# A mapping between Kanidm groups and VLANS
radius_groups = [{ spn = "radius_access_allowed@idm.example.com", vlan = 10 }]
# A mapping of clients and their authentication tokens
radius_clients = [
{ name = "test", ipaddr = "127.0.0.1", secret = "testing123" },
{ name = "docker", ipaddr = "172.17.0.0/16", secret = "testing123" },
]
# radius_cert_path = "/etc/raddb/certs/cert.pem"
# the signing key for radius TLS
# radius_key_path = "/etc/raddb/certs/key.pem"
radius_ca_path = "/data/ca.pem" # Path to the kanidm ca
# radius_ca_dir = "/data/ca"

View file

@ -1,3 +1,6 @@
# The server configuration file version.
version = "2"
# The webserver bind address. Requires TLS certificates.
# If the port is set to 443 you may require the
# NET_BIND_SERVICE capability.
@ -23,7 +26,7 @@ bindaddress = "[::]:443"
# The path to the kanidm database.
db_path = "/var/lib/private/kanidm/kanidm.db"
#
# If you have a known filesystem, kanidm can tune the
# If you have a known filesystem, kanidm can tune the
# database page size to match. Valid choices are:
# [zfs, other]
# If you are unsure about this leave it as the default
@ -45,7 +48,7 @@ db_path = "/var/lib/private/kanidm/kanidm.db"
# db_arc_size = 2048
#
# TLS chain and key in pem format. Both must be present.
# If the server recieves a SIGHUP, these files will be
# If the server receives a SIGHUP, these files will be
# re-read and reloaded if their content is valid.
tls_chain = "/var/lib/private/kanidm/chain.pem"
tls_key = "/var/lib/private/kanidm/key.pem"
@ -72,7 +75,7 @@ tls_key = "/var/lib/private/kanidm/key.pem"
# credentials for accounts including but not limited to
# webauthn, oauth tokens, and more.
# If you change this value you *must* run
# `kanidmd domain_name_change` immediately after.
# `kanidmd domain rename` immediately after.
domain = "idm.example.com"
#
# The origin for webauthn. This is the url to the server,

View file

@ -1,3 +1,6 @@
# The server configuration file version.
version = "2"
# The webserver bind address. Requires TLS certificates.
# If the port is set to 443 you may require the
# NET_BIND_SERVICE capability.
@ -23,7 +26,7 @@ bindaddress = "[::]:8443"
# The path to the kanidm database.
db_path = "/data/kanidm.db"
#
# If you have a known filesystem, kanidm can tune the
# If you have a known filesystem, kanidm can tune the
# database page size to match. Valid choices are:
# [zfs, other]
# If you are unsure about this leave it as the default
@ -44,7 +47,9 @@ db_path = "/data/kanidm.db"
# memory pressure on your system.
# db_arc_size = 2048
#
# TLS chain and key in pem format. Both must be present
# TLS chain and key in pem format. Both must be present.
# If the server receives a SIGHUP, these files will be
# re-read and reloaded if their content is valid.
tls_chain = "/data/chain.pem"
tls_key = "/data/key.pem"
#

View file

@ -3,6 +3,9 @@
# The configuration file version.
version = '2'
# ⚠️ Ensure that you have the [kanidm] or other provider sections below
# configured else accounts from remote sources will not be available.
# Kanidm unix will bind all cached credentials to a local Hardware Security
# Module (HSM) to prevent exfiltration and attacks against these. In addition,
# any internal private keys will also be stored in this HSM.
@ -136,6 +139,7 @@ version = '2'
# allow_local_account_override = ["admin"]
# ========================================
# This section enables the Kanidm provider
[kanidm]

View file

@ -1,17 +1,19 @@
## Kanidm Unixd minimal Service Configuration - /etc/kanidm/unixd
# Kanidm Unixd minimal Service Configuration - /etc/kanidm/unixd
# For a full example and documentation, see /usr/share/kanidm-unixd/unixd
# or `example/unixd` in the source repository.
# or `example/unixd` in the source repository
version = '2'
[kanidm]
# default_shell = "/bin/sh"
# home_attr = "uuid"
# home_alias = "spn"
# use_etc_skel = false
# Defines a set of POSIX groups where membership of any of these groups
# will be allowed to login via PAM.
# Replace your group below and uncomment this line:
#pam_allowed_login_groups = ["your_posix_login_group"]
# will be allowed to login via PAM
#
# WITHOUT THIS SET, NOBODY WILL BE ABLE TO LOG IN VIA PAM
#
# Replace your group below and uncomment this line
# pam_allowed_login_groups = ["your_posix_login_group"]

View file

@ -1,4 +1,5 @@
use crate::{ClientError, KanidmClient};
use kanidm_proto::constants::ATTR_DOMAIN_ALLOW_EASTER_EGGS;
use kanidm_proto::internal::ImageValue;
use reqwest::multipart;
@ -8,6 +9,14 @@ impl KanidmClient {
self.perform_delete_request("/v1/domain/_image").await
}
pub async fn idm_set_domain_allow_easter_eggs(&self, enable: bool) -> Result<(), ClientError> {
self.perform_put_request(
&format!("{}{}", "/v1/domain/_attr/", ATTR_DOMAIN_ALLOW_EASTER_EGGS),
vec![enable.to_string()],
)
.await
}
/// Add or update the domain logo/image
pub async fn idm_domain_update_image(&self, image: ImageValue) -> Result<(), ClientError> {
let file_content_type = image.filetype.as_content_type_str();

View file

@ -37,6 +37,14 @@ impl KanidmClient {
.await
}
pub async fn group_account_policy_authsession_expiry_reset(
&self,
id: &str,
) -> Result<(), ClientError> {
self.perform_delete_request(&format!("/v1/group/{}/_attr/authsession_expiry", id))
.await
}
pub async fn group_account_policy_credential_type_minimum_set(
&self,
id: &str,
@ -61,6 +69,17 @@ impl KanidmClient {
.await
}
pub async fn group_account_policy_password_minimum_length_reset(
&self,
id: &str,
) -> Result<(), ClientError> {
self.perform_delete_request(&format!(
"/v1/group/{}/_attr/auth_password_minimum_length",
id
))
.await
}
pub async fn group_account_policy_privilege_expiry_set(
&self,
id: &str,
@ -73,6 +92,14 @@ impl KanidmClient {
.await
}
pub async fn group_account_policy_privilege_expiry_reset(
&self,
id: &str,
) -> Result<(), ClientError> {
self.perform_delete_request(&format!("/v1/group/{}/_attr/privilege_expiry", id))
.await
}
pub async fn group_account_policy_webauthn_attestation_set(
&self,
id: &str,
@ -85,6 +112,17 @@ impl KanidmClient {
.await
}
pub async fn group_account_policy_webauthn_attestation_reset(
&self,
id: &str,
) -> Result<(), ClientError> {
self.perform_delete_request(&format!(
"/v1/group/{}/_attr/webauthn_attestation_ca_list",
id
))
.await
}
pub async fn group_account_policy_limit_search_max_results(
&self,
id: &str,
@ -97,6 +135,14 @@ impl KanidmClient {
.await
}
pub async fn group_account_policy_limit_search_max_results_reset(
&self,
id: &str,
) -> Result<(), ClientError> {
self.perform_delete_request(&format!("/v1/group/{}/_attr/limit_search_max_results", id))
.await
}
pub async fn group_account_policy_limit_search_max_filter_test(
&self,
id: &str,
@ -109,6 +155,17 @@ impl KanidmClient {
.await
}
pub async fn group_account_policy_limit_search_max_filter_test_reset(
&self,
id: &str,
) -> Result<(), ClientError> {
self.perform_delete_request(&format!(
"/v1/group/{}/_attr/limit_search_max_filter_test",
id
))
.await
}
pub async fn group_account_policy_allow_primary_cred_fallback(
&self,
id: &str,
@ -138,4 +195,20 @@ impl KanidmClient {
self.perform_get_request(&format!("/v1/group/{}/_attr/mail", id))
.await
}
pub async fn idm_group_purge_description(&self, id: &str) -> Result<(), ClientError> {
self.idm_group_purge_attr(id, "description").await
}
pub async fn idm_group_set_description(
&self,
id: &str,
description: &str,
) -> Result<(), ClientError> {
self.perform_put_request(
&format!("/v1/group/{}/_attr/description", id),
&[description],
)
.await
}
}

View file

@ -27,11 +27,12 @@ use std::time::Duration;
use compact_jwt::Jwk;
pub use http;
use kanidm_proto::constants::uri::V1_AUTH_VALID;
use kanidm_proto::constants::{
ATTR_DOMAIN_DISPLAY_NAME, ATTR_DOMAIN_LDAP_BASEDN, ATTR_DOMAIN_SSID, ATTR_ENTRY_MANAGED_BY,
ATTR_KEY_ACTION_REVOKE, ATTR_LDAP_ALLOW_UNIX_PW_BIND, ATTR_NAME, CLIENT_TOKEN_CACHE, KOPID,
KSESSIONID, KVERSION,
ATTR_KEY_ACTION_REVOKE, ATTR_LDAP_ALLOW_UNIX_PW_BIND, ATTR_LDAP_MAX_QUERYABLE_ATTRS, ATTR_NAME,
CLIENT_TOKEN_CACHE, KOPID, KSESSIONID, KVERSION,
};
use kanidm_proto::internal::*;
use kanidm_proto::v1::*;
@ -94,7 +95,7 @@ pub struct KanidmClientConfigInstance {
pub verify_hostnames: Option<bool>,
/// Whether to verify the Certificate Authority details of the server's TLS certificate, defaults to `true`.
///
/// Environment variable is slightly inverted - `KANIDM_SKIP_HOSTNAME_VERIFICATION`.
/// Environment variable is slightly inverted - `KANIDM_ACCEPT_INVALID_CERTS`.
pub verify_ca: Option<bool>,
/// Optionally you can specify the path of a CA certificate to use for verifying the server, if you're not using one trusted by your system certificate store.
///
@ -137,6 +138,7 @@ pub struct KanidmClientBuilder {
use_system_proxies: bool,
/// Where to store auth tokens, only use in testing!
token_cache_path: Option<String>,
disable_system_ca_store: bool,
}
impl Display for KanidmClientBuilder {
@ -170,33 +172,6 @@ impl Display for KanidmClientBuilder {
}
}
#[test]
fn test_kanidmclientbuilder_display() {
let defaultclient = KanidmClientBuilder::default();
println!("{}", defaultclient);
assert!(defaultclient.to_string().contains("verify_ca"));
let testclient = KanidmClientBuilder {
address: Some("https://example.com".to_string()),
verify_ca: true,
verify_hostnames: true,
ca: None,
connect_timeout: Some(420),
request_timeout: Some(69),
use_system_proxies: true,
token_cache_path: Some(CLIENT_TOKEN_CACHE.to_string()),
};
println!("testclient {}", testclient);
assert!(testclient.to_string().contains("verify_ca: true"));
assert!(testclient.to_string().contains("verify_hostnames: true"));
let badness = testclient.danger_accept_invalid_hostnames(true);
let badness = badness.danger_accept_invalid_certs(true);
println!("badness: {}", badness);
assert!(badness.to_string().contains("verify_ca: false"));
assert!(badness.to_string().contains("verify_hostnames: false"));
}
#[derive(Debug)]
pub struct KanidmClient {
pub(crate) client: reqwest::Client,
@ -233,6 +208,7 @@ impl KanidmClientBuilder {
request_timeout: None,
use_system_proxies: true,
token_cache_path: None,
disable_system_ca_store: false,
}
}
@ -290,6 +266,7 @@ impl KanidmClientBuilder {
request_timeout,
use_system_proxies,
token_cache_path,
disable_system_ca_store,
} = self;
// Process and apply all our options if they exist.
let address = match kcc.uri {
@ -316,6 +293,7 @@ impl KanidmClientBuilder {
request_timeout,
use_system_proxies,
token_cache_path,
disable_system_ca_store,
})
}
@ -416,6 +394,16 @@ impl KanidmClientBuilder {
}
}
/// Enable or disable the native ca roots. By default these roots are enabled.
pub fn enable_native_ca_roots(self, enable: bool) -> Self {
KanidmClientBuilder {
// We have to flip the bool state here due to Default on bool being false
// and we want our options to be positive to a native speaker.
disable_system_ca_store: !enable,
..self
}
}
pub fn danger_accept_invalid_hostnames(self, accept_invalid_hostnames: bool) -> Self {
KanidmClientBuilder {
// We have to flip the bool state here due to english language.
@ -453,6 +441,13 @@ impl KanidmClientBuilder {
}
}
pub fn set_token_cache_path(self, token_cache_path: Option<String>) -> Self {
KanidmClientBuilder {
token_cache_path,
..self
}
}
#[allow(clippy::result_unit_err)]
pub fn add_root_certificate_filepath(self, ca_path: &str) -> Result<Self, ClientError> {
//Okay we have a ca to add. Let's read it in and setup.
@ -520,6 +515,7 @@ impl KanidmClientBuilder {
// implement sticky sessions with cookies.
.cookie_store(true)
.cookie_provider(client_cookies.clone())
.tls_built_in_native_certs(!self.disable_system_ca_store)
.danger_accept_invalid_hostnames(!self.verify_hostnames)
.danger_accept_invalid_certs(!self.verify_ca);
@ -572,32 +568,6 @@ impl KanidmClientBuilder {
}
}
#[test]
fn test_make_url() {
use kanidm_proto::constants::DEFAULT_SERVER_ADDRESS;
let client: KanidmClient = KanidmClientBuilder::new()
.address(format!("https://{}", DEFAULT_SERVER_ADDRESS))
.build()
.unwrap();
assert_eq!(
client.get_url(),
Url::parse(&format!("https://{}", DEFAULT_SERVER_ADDRESS)).unwrap()
);
assert_eq!(
client.make_url("/hello"),
Url::parse(&format!("https://{}/hello", DEFAULT_SERVER_ADDRESS)).unwrap()
);
let client: KanidmClient = KanidmClientBuilder::new()
.address(format!("https://{}/cheese/", DEFAULT_SERVER_ADDRESS))
.build()
.unwrap();
assert_eq!(
client.make_url("hello"),
Url::parse(&format!("https://{}/cheese/hello", DEFAULT_SERVER_ADDRESS)).unwrap()
);
}
/// This is probably pretty jank but it works and was pulled from here:
/// <https://github.com/seanmonstar/reqwest/issues/1602#issuecomment-1220996681>
fn find_reqwest_error_source<E: std::error::Error + 'static>(
@ -616,6 +586,11 @@ fn find_reqwest_error_source<E: std::error::Error + 'static>(
}
impl KanidmClient {
/// Access the underlying reqwest client that has been configured for this Kanidm server
pub fn client(&self) -> &reqwest::Client {
&self.client
}
pub fn get_origin(&self) -> &Url {
&self.origin
}
@ -2075,6 +2050,18 @@ impl KanidmClient {
.await
}
/// Sets the maximum number of LDAP attributes that can be queryed in a single operation
pub async fn idm_domain_set_ldap_max_queryable_attrs(
&self,
max_queryable_attrs: usize,
) -> Result<(), ClientError> {
self.perform_put_request(
&format!("/v1/domain/_attr/{}", ATTR_LDAP_MAX_QUERYABLE_ATTRS),
vec![max_queryable_attrs.to_string()],
)
.await
}
pub async fn idm_set_ldap_allow_unix_password_bind(
&self,
enable: bool,
@ -2155,31 +2142,97 @@ impl KanidmClient {
}
}
#[tokio::test]
async fn test_no_client_version_check_on_502() {
let res = reqwest::Response::from(
http::Response::builder()
.status(StatusCode::GATEWAY_TIMEOUT)
.body("")
.unwrap(),
);
let client = KanidmClientBuilder::new()
.address("http://localhost:8080".to_string())
.build()
.expect("Failed to build client");
eprintln!("This should pass because we are returning 504 and shouldn't check version...");
client.expect_version(&res).await;
#[cfg(test)]
mod tests {
use super::{KanidmClient, KanidmClientBuilder};
use kanidm_proto::constants::CLIENT_TOKEN_CACHE;
use reqwest::StatusCode;
use url::Url;
let res = reqwest::Response::from(
http::Response::builder()
.status(StatusCode::BAD_GATEWAY)
.body("")
.unwrap(),
);
let client = KanidmClientBuilder::new()
.address("http://localhost:8080".to_string())
.build()
.expect("Failed to build client");
eprintln!("This should pass because we are returning 502 and shouldn't check version...");
client.expect_version(&res).await;
#[tokio::test]
async fn test_no_client_version_check_on_502() {
let res = reqwest::Response::from(
http::Response::builder()
.status(StatusCode::GATEWAY_TIMEOUT)
.body("")
.unwrap(),
);
let client = KanidmClientBuilder::new()
.address("http://localhost:8080".to_string())
.enable_native_ca_roots(false)
.build()
.expect("Failed to build client");
eprintln!("This should pass because we are returning 504 and shouldn't check version...");
client.expect_version(&res).await;
let res = reqwest::Response::from(
http::Response::builder()
.status(StatusCode::BAD_GATEWAY)
.body("")
.unwrap(),
);
let client = KanidmClientBuilder::new()
.address("http://localhost:8080".to_string())
.enable_native_ca_roots(false)
.build()
.expect("Failed to build client");
eprintln!("This should pass because we are returning 502 and shouldn't check version...");
client.expect_version(&res).await;
}
#[test]
fn test_make_url() {
use kanidm_proto::constants::DEFAULT_SERVER_ADDRESS;
let client: KanidmClient = KanidmClientBuilder::new()
.address(format!("https://{}", DEFAULT_SERVER_ADDRESS))
.enable_native_ca_roots(false)
.build()
.unwrap();
assert_eq!(
client.get_url(),
Url::parse(&format!("https://{}", DEFAULT_SERVER_ADDRESS)).unwrap()
);
assert_eq!(
client.make_url("/hello"),
Url::parse(&format!("https://{}/hello", DEFAULT_SERVER_ADDRESS)).unwrap()
);
let client: KanidmClient = KanidmClientBuilder::new()
.address(format!("https://{}/cheese/", DEFAULT_SERVER_ADDRESS))
.enable_native_ca_roots(false)
.build()
.unwrap();
assert_eq!(
client.make_url("hello"),
Url::parse(&format!("https://{}/cheese/hello", DEFAULT_SERVER_ADDRESS)).unwrap()
);
}
#[test]
fn test_kanidmclientbuilder_display() {
let defaultclient = KanidmClientBuilder::default();
println!("{}", defaultclient);
assert!(defaultclient.to_string().contains("verify_ca"));
let testclient = KanidmClientBuilder {
address: Some("https://example.com".to_string()),
verify_ca: true,
verify_hostnames: true,
ca: None,
connect_timeout: Some(420),
request_timeout: Some(69),
use_system_proxies: true,
token_cache_path: Some(CLIENT_TOKEN_CACHE.to_string()),
disable_system_ca_store: false,
};
println!("testclient {}", testclient);
assert!(testclient.to_string().contains("verify_ca: true"));
assert!(testclient.to_string().contains("verify_hostnames: true"));
let badness = testclient.danger_accept_invalid_hostnames(true);
let badness = badness.danger_accept_invalid_certs(true);
println!("badness: {}", badness);
assert!(badness.to_string().contains("verify_ca: false"));
assert!(badness.to_string().contains("verify_hostnames: false"));
}
}

View file

@ -434,6 +434,8 @@ impl KanidmClient {
id: &str,
origin: &Url,
) -> Result<(), ClientError> {
// TODO: should we normalise loopback origins, so when a user specifies `http://localhost/foo` we store it as `http://[::1]/foo`?
let url_to_add = &[origin.as_str()];
self.perform_post_request(
format!("/v1/oauth2/{}/_attr/{}", id, ATTR_OAUTH2_RS_ORIGIN).as_str(),

View file

@ -33,5 +33,12 @@ tracing = { workspace = true }
uuid = { workspace = true }
x509-cert = { workspace = true, features = ["pem"] }
md-5 = { workspace = true }
sha-crypt = { workspace = true }
[dev-dependencies]
sketching = { workspace = true }
[package.metadata.cargo-machete]
ignored = ["openssl-sys"]

View file

@ -0,0 +1,99 @@
use md5::{Digest, Md5};
use std::cmp::min;
/// Maximium salt length.
const MD5_MAGIC: &str = "$1$";
const MD5_TRANSPOSE: &[u8] = b"\x0c\x06\x00\x0d\x07\x01\x0e\x08\x02\x0f\x09\x03\x05\x0a\x04\x0b";
const CRYPT_HASH64: &[u8] = b"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
pub fn md5_sha2_hash64_encode(bs: &[u8]) -> String {
let ngroups = bs.len().div_ceil(3);
let mut out = String::with_capacity(ngroups * 4);
for g in 0..ngroups {
let mut g_idx = g * 3;
let mut enc = 0u32;
for _ in 0..3 {
let b = (if g_idx < bs.len() { bs[g_idx] } else { 0 }) as u32;
enc >>= 8;
enc |= b << 16;
g_idx += 1;
}
for _ in 0..4 {
out.push(char::from_u32(CRYPT_HASH64[(enc & 0x3F) as usize] as u32).unwrap_or('!'));
enc >>= 6;
}
}
match bs.len() % 3 {
1 => {
out.pop();
out.pop();
}
2 => {
out.pop();
}
_ => (),
}
out
}
pub fn do_md5_crypt(pass: &[u8], salt: &[u8]) -> Vec<u8> {
let mut dgst_b = Md5::new();
dgst_b.update(pass);
dgst_b.update(salt);
dgst_b.update(pass);
let mut hash_b = dgst_b.finalize();
let mut dgst_a = Md5::new();
dgst_a.update(pass);
dgst_a.update(MD5_MAGIC.as_bytes());
dgst_a.update(salt);
let mut plen = pass.len();
while plen > 0 {
dgst_a.update(&hash_b[..min(plen, 16)]);
if plen < 16 {
break;
}
plen -= 16;
}
plen = pass.len();
while plen > 0 {
if plen & 1 == 0 {
dgst_a.update(&pass[..1])
} else {
dgst_a.update([0u8])
}
plen >>= 1;
}
let mut hash_a = dgst_a.finalize();
for r in 0..1000 {
let mut dgst_a = Md5::new();
if r % 2 == 1 {
dgst_a.update(pass);
} else {
dgst_a.update(hash_a);
}
if r % 3 > 0 {
dgst_a.update(salt);
}
if r % 7 > 0 {
dgst_a.update(pass);
}
if r % 2 == 0 {
dgst_a.update(pass);
} else {
dgst_a.update(hash_a);
}
hash_a = dgst_a.finalize();
}
for (i, &ti) in MD5_TRANSPOSE.iter().enumerate() {
hash_b[i] = hash_a[ti as usize];
}
md5_sha2_hash64_encode(&hash_b).into_bytes()
}

View file

@ -11,26 +11,24 @@
#![deny(clippy::unreachable)]
use argon2::{Algorithm, Argon2, Params, PasswordHash, Version};
use base64::engine::general_purpose;
use base64::engine::GeneralPurpose;
use base64::{alphabet, Engine};
use tracing::{debug, error, trace, warn};
use base64::engine::general_purpose;
use base64urlsafedata::Base64UrlSafeData;
use rand::Rng;
use serde::{Deserialize, Serialize};
use std::fmt;
use std::time::{Duration, Instant};
use kanidm_hsm_crypto::{HmacKey, Tpm};
use kanidm_proto::internal::OperationError;
use openssl::error::ErrorStack as OpenSSLErrorStack;
use openssl::hash::{self, MessageDigest};
use openssl::nid::Nid;
use openssl::pkcs5::pbkdf2_hmac;
use openssl::sha::{Sha1, Sha256, Sha512};
use rand::Rng;
use serde::{Deserialize, Serialize};
use std::fmt;
use std::time::{Duration, Instant};
use tracing::{debug, error, trace, warn};
use kanidm_hsm_crypto::{HmacKey, Tpm};
mod crypt_md5;
pub mod mtls;
pub mod prelude;
pub mod serialise;
@ -84,6 +82,7 @@ pub enum CryptoError {
Argon2,
Argon2Version,
Argon2Parameters,
Crypt,
}
impl From<OpenSSLErrorStack> for CryptoError {
@ -137,65 +136,15 @@ pub enum DbPasswordV1 {
SHA512(Vec<u8>),
SSHA512(Vec<u8>, Vec<u8>),
NT_MD4(Vec<u8>),
}
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
#[allow(non_camel_case_types)]
pub enum ReplPasswordV1 {
TPM_ARGON2ID {
m_cost: u32,
t_cost: u32,
p_cost: u32,
version: u32,
salt: Base64UrlSafeData,
key: Base64UrlSafeData,
CRYPT_MD5 {
s: Base64UrlSafeData,
h: Base64UrlSafeData,
},
ARGON2ID {
m_cost: u32,
t_cost: u32,
p_cost: u32,
version: u32,
salt: Base64UrlSafeData,
key: Base64UrlSafeData,
CRYPT_SHA256 {
h: String,
},
PBKDF2 {
cost: usize,
salt: Base64UrlSafeData,
hash: Base64UrlSafeData,
},
PBKDF2_SHA1 {
cost: usize,
salt: Base64UrlSafeData,
hash: Base64UrlSafeData,
},
PBKDF2_SHA512 {
cost: usize,
salt: Base64UrlSafeData,
hash: Base64UrlSafeData,
},
SHA1 {
hash: Base64UrlSafeData,
},
SSHA1 {
salt: Base64UrlSafeData,
hash: Base64UrlSafeData,
},
SHA256 {
hash: Base64UrlSafeData,
},
SSHA256 {
salt: Base64UrlSafeData,
hash: Base64UrlSafeData,
},
SHA512 {
hash: Base64UrlSafeData,
},
SSHA512 {
salt: Base64UrlSafeData,
hash: Base64UrlSafeData,
},
NT_MD4 {
hash: Base64UrlSafeData,
CRYPT_SHA512 {
h: String,
},
}
@ -214,6 +163,9 @@ impl fmt::Debug for DbPasswordV1 {
DbPasswordV1::SHA512(_) => write!(f, "SHA512"),
DbPasswordV1::SSHA512(_, _) => write!(f, "SSHA512"),
DbPasswordV1::NT_MD4(_) => write!(f, "NT_MD4"),
DbPasswordV1::CRYPT_MD5 { .. } => write!(f, "CRYPT_MD5"),
DbPasswordV1::CRYPT_SHA256 { .. } => write!(f, "CRYPT_SHA256"),
DbPasswordV1::CRYPT_SHA512 { .. } => write!(f, "CRYPT_SHA512"),
}
}
}
@ -436,6 +388,16 @@ enum Kdf {
SSHA512(Vec<u8>, Vec<u8>),
// hash
NT_MD4(Vec<u8>),
CRYPT_MD5 {
s: Vec<u8>,
h: Vec<u8>,
},
CRYPT_SHA256 {
h: String,
},
CRYPT_SHA512 {
h: String,
},
}
#[derive(Clone, Debug, PartialEq)]
@ -498,78 +460,17 @@ impl TryFrom<DbPasswordV1> for Password {
DbPasswordV1::NT_MD4(h) => Ok(Password {
material: Kdf::NT_MD4(h),
}),
}
}
}
impl TryFrom<&ReplPasswordV1> for Password {
type Error = ();
fn try_from(value: &ReplPasswordV1) -> Result<Self, Self::Error> {
match value {
ReplPasswordV1::TPM_ARGON2ID {
m_cost,
t_cost,
p_cost,
version,
salt,
key,
} => Ok(Password {
material: Kdf::TPM_ARGON2ID {
m_cost: *m_cost,
t_cost: *t_cost,
p_cost: *p_cost,
version: *version,
salt: salt.to_vec(),
key: key.to_vec(),
DbPasswordV1::CRYPT_MD5 { s, h } => Ok(Password {
material: Kdf::CRYPT_MD5 {
s: s.into(),
h: h.into(),
},
}),
ReplPasswordV1::ARGON2ID {
m_cost,
t_cost,
p_cost,
version,
salt,
key,
} => Ok(Password {
material: Kdf::ARGON2ID {
m_cost: *m_cost,
t_cost: *t_cost,
p_cost: *p_cost,
version: *version,
salt: salt.to_vec(),
key: key.to_vec(),
},
DbPasswordV1::CRYPT_SHA256 { h } => Ok(Password {
material: Kdf::CRYPT_SHA256 { h },
}),
ReplPasswordV1::PBKDF2 { cost, salt, hash } => Ok(Password {
material: Kdf::PBKDF2(*cost, salt.to_vec(), hash.to_vec()),
}),
ReplPasswordV1::PBKDF2_SHA1 { cost, salt, hash } => Ok(Password {
material: Kdf::PBKDF2_SHA1(*cost, salt.to_vec(), hash.to_vec()),
}),
ReplPasswordV1::PBKDF2_SHA512 { cost, salt, hash } => Ok(Password {
material: Kdf::PBKDF2_SHA512(*cost, salt.to_vec(), hash.to_vec()),
}),
ReplPasswordV1::SHA1 { hash } => Ok(Password {
material: Kdf::SHA1(hash.to_vec()),
}),
ReplPasswordV1::SSHA1 { salt, hash } => Ok(Password {
material: Kdf::SSHA1(salt.to_vec(), hash.to_vec()),
}),
ReplPasswordV1::SHA256 { hash } => Ok(Password {
material: Kdf::SHA256(hash.to_vec()),
}),
ReplPasswordV1::SSHA256 { salt, hash } => Ok(Password {
material: Kdf::SSHA256(salt.to_vec(), hash.to_vec()),
}),
ReplPasswordV1::SHA512 { hash } => Ok(Password {
material: Kdf::SHA512(hash.to_vec()),
}),
ReplPasswordV1::SSHA512 { salt, hash } => Ok(Password {
material: Kdf::SSHA512(salt.to_vec(), hash.to_vec()),
}),
ReplPasswordV1::NT_MD4 { hash } => Ok(Password {
material: Kdf::NT_MD4(hash.to_vec()),
DbPasswordV1::CRYPT_SHA512 { h } => Ok(Password {
material: Kdf::CRYPT_SHA256 { h },
}),
}
}
@ -662,9 +563,47 @@ impl TryFrom<&str> for Password {
});
}
// Test 389ds formats
// Test 389ds/openldap formats. Shout outs openldap which sometimes makes these
// lowercase.
if let Some(ds_ssha1) = value.strip_prefix("{SHA}") {
if let Some(crypt) = value
.strip_prefix("{crypt}")
.or_else(|| value.strip_prefix("{CRYPT}"))
{
if let Some(crypt_md5_phc) = crypt.strip_prefix("$1$") {
let (salt, hash) = crypt_md5_phc.split_once('$').ok_or(())?;
// These are a hash64 format, so leave them as bytes, don't try
// to decode.
let s = salt.as_bytes().to_vec();
let h = hash.as_bytes().to_vec();
return Ok(Password {
material: Kdf::CRYPT_MD5 { s, h },
});
}
if crypt.starts_with("$5$") {
return Ok(Password {
material: Kdf::CRYPT_SHA256 {
h: crypt.to_string(),
},
});
}
if crypt.starts_with("$6$") {
return Ok(Password {
material: Kdf::CRYPT_SHA512 {
h: crypt.to_string(),
},
});
}
} // End crypt
if let Some(ds_ssha1) = value
.strip_prefix("{SHA}")
.or_else(|| value.strip_prefix("{sha}"))
{
let h = general_purpose::STANDARD.decode(ds_ssha1).map_err(|_| ())?;
if h.len() != DS_SHA1_HASH_LEN {
return Err(());
@ -674,7 +613,10 @@ impl TryFrom<&str> for Password {
});
}
if let Some(ds_ssha1) = value.strip_prefix("{SSHA}") {
if let Some(ds_ssha1) = value
.strip_prefix("{SSHA}")
.or_else(|| value.strip_prefix("{ssha}"))
{
let sh = general_purpose::STANDARD.decode(ds_ssha1).map_err(|_| ())?;
let (h, s) = sh.split_at(DS_SHA1_HASH_LEN);
if s.len() != DS_SHA_SALT_LEN {
@ -685,7 +627,10 @@ impl TryFrom<&str> for Password {
});
}
if let Some(ds_ssha256) = value.strip_prefix("{SHA256}") {
if let Some(ds_ssha256) = value
.strip_prefix("{SHA256}")
.or_else(|| value.strip_prefix("{sha256}"))
{
let h = general_purpose::STANDARD
.decode(ds_ssha256)
.map_err(|_| ())?;
@ -697,7 +642,10 @@ impl TryFrom<&str> for Password {
});
}
if let Some(ds_ssha256) = value.strip_prefix("{SSHA256}") {
if let Some(ds_ssha256) = value
.strip_prefix("{SSHA256}")
.or_else(|| value.strip_prefix("{ssha256}"))
{
let sh = general_purpose::STANDARD
.decode(ds_ssha256)
.map_err(|_| ())?;
@ -710,7 +658,10 @@ impl TryFrom<&str> for Password {
});
}
if let Some(ds_ssha512) = value.strip_prefix("{SHA512}") {
if let Some(ds_ssha512) = value
.strip_prefix("{SHA512}")
.or_else(|| value.strip_prefix("{sha512}"))
{
let h = general_purpose::STANDARD
.decode(ds_ssha512)
.map_err(|_| ())?;
@ -722,7 +673,10 @@ impl TryFrom<&str> for Password {
});
}
if let Some(ds_ssha512) = value.strip_prefix("{SSHA512}") {
if let Some(ds_ssha512) = value
.strip_prefix("{SSHA512}")
.or_else(|| value.strip_prefix("{ssha512}"))
{
let sh = general_purpose::STANDARD
.decode(ds_ssha512)
.map_err(|_| ())?;
@ -1223,6 +1177,20 @@ impl Password {
})
.map(|chal_key| chal_key.as_ref() == key)
}
(Kdf::CRYPT_MD5 { s, h }, _) => {
let chal_key = crypt_md5::do_md5_crypt(cleartext.as_bytes(), s);
Ok(chal_key == *h)
}
(Kdf::CRYPT_SHA256 { h }, _) => {
let is_valid = sha_crypt::sha256_check(cleartext, h.as_str()).is_ok();
Ok(is_valid)
}
(Kdf::CRYPT_SHA512 { h }, _) => {
let is_valid = sha_crypt::sha512_check(cleartext, h.as_str()).is_ok();
Ok(is_valid)
}
}
}
@ -1274,80 +1242,12 @@ impl Password {
Kdf::SHA512(hash) => DbPasswordV1::SHA512(hash.clone()),
Kdf::SSHA512(salt, hash) => DbPasswordV1::SSHA512(salt.clone(), hash.clone()),
Kdf::NT_MD4(hash) => DbPasswordV1::NT_MD4(hash.clone()),
}
}
pub fn to_repl_v1(&self) -> ReplPasswordV1 {
match &self.material {
Kdf::TPM_ARGON2ID {
m_cost,
t_cost,
p_cost,
version,
salt,
key,
} => ReplPasswordV1::TPM_ARGON2ID {
m_cost: *m_cost,
t_cost: *t_cost,
p_cost: *p_cost,
version: *version,
salt: salt.clone().into(),
key: key.clone().into(),
},
Kdf::ARGON2ID {
m_cost,
t_cost,
p_cost,
version,
salt,
key,
} => ReplPasswordV1::ARGON2ID {
m_cost: *m_cost,
t_cost: *t_cost,
p_cost: *p_cost,
version: *version,
salt: salt.clone().into(),
key: key.clone().into(),
},
Kdf::PBKDF2(cost, salt, hash) => ReplPasswordV1::PBKDF2 {
cost: *cost,
salt: salt.clone().into(),
hash: hash.clone().into(),
},
Kdf::PBKDF2_SHA1(cost, salt, hash) => ReplPasswordV1::PBKDF2_SHA1 {
cost: *cost,
salt: salt.clone().into(),
hash: hash.clone().into(),
},
Kdf::PBKDF2_SHA512(cost, salt, hash) => ReplPasswordV1::PBKDF2_SHA512 {
cost: *cost,
salt: salt.clone().into(),
hash: hash.clone().into(),
},
Kdf::SHA1(hash) => ReplPasswordV1::SHA1 {
hash: hash.clone().into(),
},
Kdf::SSHA1(salt, hash) => ReplPasswordV1::SSHA1 {
salt: salt.clone().into(),
hash: hash.clone().into(),
},
Kdf::SHA256(hash) => ReplPasswordV1::SHA256 {
hash: hash.clone().into(),
},
Kdf::SSHA256(salt, hash) => ReplPasswordV1::SSHA256 {
salt: salt.clone().into(),
hash: hash.clone().into(),
},
Kdf::SHA512(hash) => ReplPasswordV1::SHA512 {
hash: hash.clone().into(),
},
Kdf::SSHA512(salt, hash) => ReplPasswordV1::SSHA512 {
salt: salt.clone().into(),
hash: hash.clone().into(),
},
Kdf::NT_MD4(hash) => ReplPasswordV1::NT_MD4 {
hash: hash.clone().into(),
Kdf::CRYPT_MD5 { s, h } => DbPasswordV1::CRYPT_MD5 {
s: s.clone().into(),
h: h.clone().into(),
},
Kdf::CRYPT_SHA256 { h } => DbPasswordV1::CRYPT_SHA256 { h: h.clone() },
Kdf::CRYPT_SHA512 { h } => DbPasswordV1::CRYPT_SHA512 { h: h.clone() },
}
}
@ -1383,7 +1283,10 @@ impl Password {
| Kdf::SSHA256(_, _)
| Kdf::SHA512(_)
| Kdf::SSHA512(_, _)
| Kdf::NT_MD4(_) => true,
| Kdf::NT_MD4(_)
| Kdf::CRYPT_MD5 { .. }
| Kdf::CRYPT_SHA256 { .. }
| Kdf::CRYPT_SHA512 { .. } => true,
}
}
}
@ -1441,8 +1344,12 @@ mod tests {
#[test]
fn test_password_from_ds_sha1() {
let im_pw = "{SHA}W6ph5Mm5Pz8GgiULbPgzG37mj9g=";
let _r = Password::try_from(im_pw).expect("Failed to parse");
let im_pw = "{sha}W6ph5Mm5Pz8GgiULbPgzG37mj9g=";
let password = "password";
let r = Password::try_from(im_pw).expect("Failed to parse");
// Known weak, require upgrade.
assert!(r.requires_upgrade());
assert!(r.verify(password).unwrap_or(false));
@ -1451,8 +1358,12 @@ mod tests {
#[test]
fn test_password_from_ds_ssha1() {
let im_pw = "{SSHA}EyzbBiP4u4zxOrLpKTORI/RX3HC6TCTJtnVOCQ==";
let _r = Password::try_from(im_pw).expect("Failed to parse");
let im_pw = "{ssha}EyzbBiP4u4zxOrLpKTORI/RX3HC6TCTJtnVOCQ==";
let password = "password";
let r = Password::try_from(im_pw).expect("Failed to parse");
// Known weak, require upgrade.
assert!(r.requires_upgrade());
assert!(r.verify(password).unwrap_or(false));
@ -1461,8 +1372,12 @@ mod tests {
#[test]
fn test_password_from_ds_sha256() {
let im_pw = "{SHA256}XohImNooBHFR0OVvjcYpJ3NgPQ1qq73WKhHvch0VQtg=";
let _r = Password::try_from(im_pw).expect("Failed to parse");
let im_pw = "{sha256}XohImNooBHFR0OVvjcYpJ3NgPQ1qq73WKhHvch0VQtg=";
let password = "password";
let r = Password::try_from(im_pw).expect("Failed to parse");
// Known weak, require upgrade.
assert!(r.requires_upgrade());
assert!(r.verify(password).unwrap_or(false));
@ -1471,8 +1386,12 @@ mod tests {
#[test]
fn test_password_from_ds_ssha256() {
let im_pw = "{SSHA256}luYWfFJOZgxySTsJXHgIaCYww4yMpu6yest69j/wO5n5OycuHFV/GQ==";
let _r = Password::try_from(im_pw).expect("Failed to parse");
let im_pw = "{ssha256}luYWfFJOZgxySTsJXHgIaCYww4yMpu6yest69j/wO5n5OycuHFV/GQ==";
let password = "password";
let r = Password::try_from(im_pw).expect("Failed to parse");
// Known weak, require upgrade.
assert!(r.requires_upgrade());
assert!(r.verify(password).unwrap_or(false));
@ -1481,8 +1400,12 @@ mod tests {
#[test]
fn test_password_from_ds_sha512() {
let im_pw = "{SHA512}sQnzu7wkTrgkQZF+0G1hi5AI3Qmzvv0bXgc5THBqi7mAsdd4Xll27ASbRt9fEyavWi6m0QP9B8lThf+rDKy8hg==";
let _r = Password::try_from(im_pw).expect("Failed to parse");
let im_pw = "{sha512}sQnzu7wkTrgkQZF+0G1hi5AI3Qmzvv0bXgc5THBqi7mAsdd4Xll27ASbRt9fEyavWi6m0QP9B8lThf+rDKy8hg==";
let password = "password";
let r = Password::try_from(im_pw).expect("Failed to parse");
// Known weak, require upgrade.
assert!(r.requires_upgrade());
assert!(r.verify(password).unwrap_or(false));
@ -1491,8 +1414,12 @@ mod tests {
#[test]
fn test_password_from_ds_ssha512() {
let im_pw = "{SSHA512}JwrSUHkI7FTAfHRVR6KoFlSN0E3dmaQWARjZ+/UsShYlENOqDtFVU77HJLLrY2MuSp0jve52+pwtdVl2QUAHukQ0XUf5LDtM";
let _r = Password::try_from(im_pw).expect("Failed to parse");
let im_pw = "{ssha512}JwrSUHkI7FTAfHRVR6KoFlSN0E3dmaQWARjZ+/UsShYlENOqDtFVU77HJLLrY2MuSp0jve52+pwtdVl2QUAHukQ0XUf5LDtM";
let password = "password";
let r = Password::try_from(im_pw).expect("Failed to parse");
// Known weak, require upgrade.
assert!(r.requires_upgrade());
assert!(r.verify(password).unwrap_or(false));
@ -1617,6 +1544,39 @@ mod tests {
}
}
#[test]
fn test_password_from_crypt_md5() {
sketching::test_init();
let im_pw = "{crypt}$1$zaRIAsoe$7887GzjDTrst0XbDPpF5m.";
let password = "password";
let r = Password::try_from(im_pw).expect("Failed to parse");
assert!(r.requires_upgrade());
assert!(r.verify(password).unwrap_or(false));
}
#[test]
fn test_password_from_crypt_sha256() {
sketching::test_init();
let im_pw = "{crypt}$5$3UzV7Sut8EHCUxlN$41V.jtMQmFAOucqI4ImFV43r.bRLjPlN.hyfoCdmGE2";
let password = "password";
let r = Password::try_from(im_pw).expect("Failed to parse");
assert!(r.requires_upgrade());
assert!(r.verify(password).unwrap_or(false));
}
#[test]
fn test_password_from_crypt_sha512() {
sketching::test_init();
let im_pw = "{crypt}$6$aXn8azL8DXUyuMvj$9aJJC/KEUwygIpf2MTqjQa.f0MEXNg2cGFc62Fet8XpuDVDedM05CweAlxW6GWxnmHqp14CRf6zU7OQoE/bCu0";
let password = "password";
let r = Password::try_from(im_pw).expect("Failed to parse");
assert!(r.requires_upgrade());
assert!(r.verify(password).unwrap_or(false));
}
#[test]
fn test_password_argon2id_hsm_bind() {
sketching::test_init();

View file

@ -16,8 +16,5 @@ doctest = false
[dependencies]
[target.'cfg(target_family = "windows")'.dependencies]
whoami = { workspace = true }
[target.'cfg(not(target_family = "windows"))'.dependencies]
kanidm_utils_users = { workspace = true }

View file

@ -3,6 +3,9 @@ use std::fs::Metadata;
#[cfg(target_os = "freebsd")]
use std::os::freebsd::fs::MetadataExt;
#[cfg(target_os = "openbsd")]
use std::os::openbsd::fs::MetadataExt;
#[cfg(target_os = "linux")]
use std::os::linux::fs::MetadataExt;
@ -12,6 +15,9 @@ use std::os::macos::fs::MetadataExt;
#[cfg(target_os = "illumos")]
use std::os::illumos::fs::MetadataExt;
#[cfg(target_os = "android")]
use std::os::android::fs::MetadataExt;
use kanidm_utils_users::{get_current_gid, get_current_uid};
use std::fmt;

View file

@ -28,3 +28,7 @@ toml = { workspace = true }
[build-dependencies]
base64 = { workspace = true }
gix = { workspace = true, default-features = false }
[package.metadata.cargo-machete]
ignored = ["gix"]

View file

@ -1,6 +1,8 @@
htmx_ui_pkg_path = "/hpkg"
# Don't set the cpu_flags to autodetect for this platform
# cpu_flags = "none"
admin_bind_path = "/data/kanidmd.sock"
default_config_path = "/data/server.toml"
default_unix_shell_path = "/bin/false"
server_admin_bind_path = "/data/kanidmd.sock"
server_ui_pkg_path = "/hpkg"
server_config_path = "/data/server.toml"
client_config_path = "/data/config"
resolver_config_path = "/data/unixd"
resolver_unix_shell_path = "/bin/false"

View file

@ -1,6 +1,8 @@
htmx_ui_pkg_path = "../core/static"
# Set to native for developer machines.
cpu_flags = "native"
admin_bind_path = "/tmp/kanidmd.sock"
default_config_path = "../../examples/insecure_server.toml"
default_unix_shell_path = "/bin/bash"
server_admin_bind_path = "/tmp/kanidmd.sock"
server_ui_pkg_path = "../core/static"
server_config_path = "../../examples/insecure_server.toml"
client_config_path = "/etc/kanidm/config"
resolver_config_path = "/tmp/unixd"
resolver_unix_shell_path = "/bin/bash"

View file

@ -0,0 +1,14 @@
# The main difference from the release_linux profile is using
# per-package shared directories for a clearer separation and
# thus more consistent install & sysadmin experience.
# Don't set the value for autodetect
# cpu_flags = "none"
server_admin_bind_path = "/var/run/kanidmd/sock"
server_ui_pkg_path = "/usr/share/kanidmd/static"
server_config_path = "/etc/kanidmd/server.toml"
client_config_path = "/etc/kanidm/config"
# TODO: unixd should migrate to it's own config dir as part of the sparkled migration.
# No point in doing two back to back migrations.
resolver_config_path = "/etc/kanidm/unixd"
resolver_unix_shell_path = "/bin/bash"

View file

@ -0,0 +1,8 @@
# Don't set the value for autodetect
# cpu_flags = "none"
server_admin_bind_path = "/var/run/kanidmd/sock"
server_ui_pkg_path = "/usr/local/share/kanidm/ui/hpkg"
server_config_path = "/usr/local/etc/kanidm/server.toml"
client_config_path = "/usr/local/etc/kanidm/config"
resolver_config_path = "/usr/local/etc/kanidm/unixd"
resolver_unix_shell_path = "/bin/sh"

View file

@ -1,6 +1,8 @@
htmx_ui_pkg_path = "/usr/share/kanidm/ui/hpkg"
# Don't set the value for autodetect
# cpu_flags = "none"
admin_bind_path = "/var/run/kanidmd/sock"
default_config_path = "/etc/kanidm/server.toml"
default_unix_shell_path = "/bin/bash"
server_admin_bind_path = "/var/run/kanidmd/sock"
server_ui_pkg_path = "/usr/share/kanidm/ui/hpkg"
server_config_path = "/etc/kanidm/server.toml"
client_config_path = "/etc/kanidm/config"
resolver_config_path = "/etc/kanidm/unixd"
resolver_unix_shell_path = "/bin/bash"

View file

@ -54,12 +54,14 @@ impl std::fmt::Display for CpuOptLevel {
#[derive(Debug, Deserialize)]
#[serde(deny_unknown_fields)]
struct ProfileConfig {
htmx_ui_pkg_path: String,
#[serde(default)]
cpu_flags: CpuOptLevel,
admin_bind_path: String,
default_config_path: String,
default_unix_shell_path: String,
server_admin_bind_path: String,
server_config_path: String,
server_ui_pkg_path: String,
client_config_path: String,
resolver_config_path: String,
resolver_unix_shell_path: String,
}
pub fn apply_profile() {
@ -127,19 +129,27 @@ pub fn apply_profile() {
println!("cargo:rustc-env=KANIDM_PROFILE_NAME={}", profile);
println!("cargo:rustc-env=KANIDM_CPU_FLAGS={}", profile_cfg.cpu_flags);
println!(
"cargo:rustc-env=KANIDM_HTMX_UI_PKG_PATH={}",
profile_cfg.htmx_ui_pkg_path
"cargo:rustc-env=KANIDM_SERVER_UI_PKG_PATH={}",
profile_cfg.server_ui_pkg_path
);
println!(
"cargo:rustc-env=KANIDM_ADMIN_BIND_PATH={}",
profile_cfg.admin_bind_path
"cargo:rustc-env=KANIDM_SERVER_ADMIN_BIND_PATH={}",
profile_cfg.server_admin_bind_path
);
println!(
"cargo:rustc-env=KANIDM_DEFAULT_CONFIG_PATH={}",
profile_cfg.default_config_path
"cargo:rustc-env=KANIDM_SERVER_CONFIG_PATH={}",
profile_cfg.server_config_path
);
println!(
"cargo:rustc-env=KANIDM_DEFAULT_UNIX_SHELL_PATH={}",
profile_cfg.default_unix_shell_path
"cargo:rustc-env=KANIDM_CLIENT_CONFIG_PATH={}",
profile_cfg.client_config_path
);
println!(
"cargo:rustc-env=KANIDM_RESOLVER_CONFIG_PATH={}",
profile_cfg.resolver_config_path
);
println!(
"cargo:rustc-env=KANIDM_RESOLVER_UNIX_SHELL_PATH={}",
profile_cfg.resolver_unix_shell_path
);
}

View file

@ -215,7 +215,7 @@ mod tests {
struct TestBVisitor;
impl<'de> Visitor<'de> for TestBVisitor {
impl Visitor<'_> for TestBVisitor {
type Value = TestB;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {

View file

@ -17,9 +17,8 @@ test = false
doctest = false
[dependencies]
gethostname = "0.5.0"
num_enum = { workspace = true }
opentelemetry = { workspace = true, features = ["metrics", "rt-tokio"] }
opentelemetry = { workspace = true, features = ["metrics"] }
opentelemetry-otlp = { workspace = true, default-features = false, features = [
"serde",
"logs",
@ -27,9 +26,12 @@ opentelemetry-otlp = { workspace = true, default-features = false, features = [
"http-proto",
"grpc-tonic",
] }
opentelemetry_sdk = { workspace = true }
opentelemetry_sdk = { workspace = true, features = ["rt-tokio"] }
opentelemetry-semantic-conventions = { workspace = true }
serde = { workspace = true, features = ["derive"] }
tracing = { workspace = true, features = ["attributes"] }
tracing-core = { workspace = true }
tracing-forest = { workspace = true, features = [
"uuid",
"smallvec",

View file

@ -1,16 +1,26 @@
use gethostname::gethostname;
use opentelemetry::KeyValue;
use std::{str::FromStr, time::Duration};
use opentelemetry_otlp::{Protocol, WithExportConfig};
use opentelemetry_sdk::trace::{self, Sampler};
use opentelemetry_sdk::Resource;
use std::time::Duration;
use opentelemetry::{global, trace::TracerProvider as _, KeyValue};
use opentelemetry_sdk::{
trace::{Sampler, TracerProvider},
Resource,
};
use tracing::Subscriber;
use tracing_subscriber::Registry;
use tracing_subscriber::{prelude::*, EnvFilter};
use tracing_core::Level;
use tracing_subscriber::{filter::Directive, prelude::*, EnvFilter, Registry};
pub const MAX_EVENTS_PER_SPAN: u32 = 64 * 1024;
pub const MAX_ATTRIBUTES_PER_SPAN: u32 = 128;
use opentelemetry_semantic_conventions::{
attribute::{SERVICE_NAME, SERVICE_VERSION},
SCHEMA_URL,
};
// TODO: this is coming back later
// #[allow(dead_code)]
// pub fn init_metrics() -> metrics::Result<MeterProvider> {
@ -44,28 +54,26 @@ pub fn start_logging_pipeline(
// adding these filters because when you close out the process the OTLP comms layer is NOISY
let forest_filter = forest_filter
.add_directive(
"tonic=info"
.parse()
.expect("Failed to set tonic logging to info"),
Directive::from_str("tonic=info").expect("Failed to set tonic logging to info"),
)
.add_directive("h2=info".parse().expect("Failed to set h2 logging to info"))
.add_directive(
"hyper=info"
.parse()
.expect("Failed to set hyper logging to info"),
Directive::from_str("h2=info").expect("Failed to set h2 logging to info"),
)
.add_directive(
Directive::from_str("hyper=info").expect("Failed to set hyper logging to info"),
);
let forest_layer = tracing_forest::ForestLayer::default().with_filter(forest_filter);
let t_filter: EnvFilter = EnvFilter::builder()
.with_default_directive(log_filter.into())
.from_env_lossy();
let tracer = opentelemetry_otlp::new_pipeline().tracing().with_exporter(
opentelemetry_otlp::new_exporter()
.tonic()
.with_endpoint(endpoint)
.with_timeout(Duration::from_secs(5))
.with_protocol(Protocol::HttpBinary),
);
let otlp_exporter = opentelemetry_otlp::SpanExporter::builder()
.with_tonic()
.with_endpoint(endpoint)
.with_protocol(Protocol::HttpBinary)
.with_timeout(Duration::from_secs(5))
.build()
.map_err(|err| err.to_string())?;
// this env var gets set at build time, if we can pull it, add it to the metadata
let git_rev = match option_env!("KANIDM_PKG_COMMIT_REV") {
@ -74,39 +82,47 @@ pub fn start_logging_pipeline(
};
let version = format!("{}{}", env!("CARGO_PKG_VERSION"), git_rev);
let hostname = gethostname();
let hostname = hostname.to_string_lossy();
let hostname = hostname.to_lowercase();
// let hostname = gethostname::gethostname();
// let hostname = hostname.to_string_lossy();
// let hostname = hostname.to_lowercase();
let tracer = tracer
.with_trace_config(
trace::config()
// we want *everything!*
.with_sampler(Sampler::AlwaysOn)
.with_max_events_per_span(MAX_EVENTS_PER_SPAN)
.with_max_attributes_per_span(MAX_ATTRIBUTES_PER_SPAN)
.with_resource(Resource::new(vec![
KeyValue::new("service.name", service_name),
KeyValue::new("service.version", version),
KeyValue::new("host.name", hostname),
// TODO: it'd be really nice to be able to set the instance ID here, from the server UUID so we know *which* instance on this host is logging
])),
let resource = Resource::from_schema_url(
[
// TODO: it'd be really nice to be able to set the instance ID here, from the server UUID so we know *which* instance on this host is logging
KeyValue::new(SERVICE_NAME, service_name),
KeyValue::new(SERVICE_VERSION, version),
// TODO: currently marked as an experimental flag, leaving it out for now
// KeyValue::new(DEPLOYMENT_ENVIRONMENT_NAME, hostname),
],
SCHEMA_URL,
);
let provider = TracerProvider::builder()
.with_batch_exporter(otlp_exporter, opentelemetry_sdk::runtime::Tokio)
// we want *everything!*
.with_sampler(Sampler::AlwaysOn)
.with_max_events_per_span(MAX_EVENTS_PER_SPAN)
.with_max_attributes_per_span(MAX_ATTRIBUTES_PER_SPAN)
.with_resource(resource)
.build();
global::set_tracer_provider(provider.clone());
provider.tracer("tracing-otel-subscriber");
use tracing_opentelemetry::OpenTelemetryLayer;
let registry = tracing_subscriber::registry()
.with(
tracing_subscriber::filter::LevelFilter::from_level(Level::INFO)
.with_filter(t_filter),
)
.install_batch(opentelemetry::runtime::Tokio)
.map_err(|err| {
let err = format!("Failed to start OTLP pipeline: {:?}", err);
eprintln!("{}", err);
err
})?;
// Create a tracing layer with the configured tracer;
let telemetry = tracing_opentelemetry::layer()
.with_tracer(tracer)
.with_threads(true)
.with_filter(t_filter);
.with(tracing_subscriber::fmt::layer())
// .with(MetricsLayer::new(meter_provider.clone()))
.with(forest_layer)
.with(OpenTelemetryLayer::new(
provider.tracer("tracing-otel-subscriber"),
));
Ok(Box::new(
Registry::default().with(forest_layer).with(telemetry),
))
Ok(Box::new(registry))
}
None => {
let forest_layer = tracing_forest::ForestLayer::default().with_filter(forest_filter);
@ -122,7 +138,6 @@ pub struct TracingPipelineGuard {}
impl Drop for TracingPipelineGuard {
fn drop(&mut self) {
opentelemetry::global::shutdown_tracer_provider();
opentelemetry::global::shutdown_logger_provider();
eprintln!("Logging pipeline completed shutdown");
}
}

View file

@ -1,13 +1,13 @@
[package]
name = "kanidm_utils_users"
description = "Kanidm utility crate"
version.workspace = true
authors.workspace = true
rust-version.workspace = true
edition.workspace = true
license.workspace = true
homepage.workspace = true
repository.workspace = true
version = { workspace = true }
authors = { workspace = true }
rust-version = { workspace = true }
edition = { workspace = true }
license = { workspace = true }
homepage = { workspace = true }
repository = { workspace = true }
[lib]
test = true

@ -1 +1 @@
Subproject commit 942c7b69ca807cc38186b63ab02a391bac9eac7e
Subproject commit 8d7579fb543632df74e609892c69ce9f368fdd02

View file

@ -0,0 +1,4 @@
These are the FreeBSD port Makefiles and other supporting files. In the future we will submit
these to FreeBSD ports rather than maintaining them here.

View file

@ -0,0 +1,49 @@
PORTNAME= kanidm
# DISTVERSION= 1.5.0-dev
# DISTVERSIONPREFIX= v
DISTVERSION= g20250102
GH_TAGNAME= edb8cccc84e9dacd2ac31ea1162dd24c0c454c55
GH_ACCOUNT= Firstyear
CATEGORIES= security net databases
LICENSE= MPL20
LICENSE_FILE= ${WRKSRC}/LICENSE.md
MAINTAINER= william@blackhats.net.au
COMMENT= Simple and secure identity management platform
WWW= https://github.com/kanidm/kanidm/
USES= cargo ssl
USE_GITHUB= yes
ONLY_FOR_ARCHS= aarch64 amd64
CARGO_ENV= KANIDM_BUILD_PROFILE=release_freebsd
CARGO_BUILD_ARGS = -p kanidm_tools -p kanidm_unix_int -p nss_kanidm -p pam_kanidm
CARGO_INSTALL= no
USE_RC_SUBR= kanidm_unixd kanidm_unixd_tasks
USERS= _kanidm_unixd
GROUPS= _kanidm_unixd
do-install:
${INSTALL_PROGRAM} ${WRKDIR}/target/release/kanidm ${STAGEDIR}${PREFIX}/bin
${INSTALL_PROGRAM} ${WRKDIR}/target/release/kanidm-unix ${STAGEDIR}${PREFIX}/bin
${INSTALL_PROGRAM} ${WRKDIR}/target/release/kanidm_ssh_authorizedkeys ${STAGEDIR}${PREFIX}/bin
${INSTALL_PROGRAM} ${WRKDIR}/target/release/kanidm_ssh_authorizedkeys_direct ${STAGEDIR}${PREFIX}/bin
${INSTALL_PROGRAM} ${WRKDIR}/target/release/kanidm_unixd ${STAGEDIR}${PREFIX}/libexec
${INSTALL_PROGRAM} ${WRKDIR}/target/release/kanidm_unixd_tasks ${STAGEDIR}${PREFIX}/libexec
${INSTALL_LIB} ${WRKDIR}/target/release/libnss_kanidm.so ${STAGEDIR}${PREFIX}/lib/nss_kanidm.so.1
${INSTALL_LIB} ${WRKDIR}/target/release/libpam_kanidm.so ${STAGEDIR}${PREFIX}/lib
${MKDIR} ${STAGEDIR}${PREFIX}/etc
${MKDIR} ${STAGEDIR}${PREFIX}/etc/kanidm
${MKDIR} ${STAGEDIR}/var/run/kanidm-unixd
${MKDIR} ${STAGEDIR}/var/lib/kanidm-unixd
${MKDIR} ${STAGEDIR}/var/cache/kanidm-unixd
.include <bsd.port.mk>

View file

@ -0,0 +1,27 @@
#!/bin/sh
# PROVIDE: kanidm_unixd
# REQUIRE: LOGIN
# KEYWORD: shutdown
#
# Add these lines to /etc/rc.conf.local or /etc/rc.conf
# to enable this service:
#
# kanidm_unixd_enable (bool): Set to NO by default.
# Set it to YES to enable kanidm_unixd.
. /etc/rc.subr
name=kanidm_unixd
rcvar=kanidm_unixd_enable
load_rc_config $name
: ${kanidm_unixd_enable:="NO"}
pidfile="/var/run/kanidm-unixd.pid"
command=/usr/sbin/daemon
command_args="-u _kanidm_unixd -p /var/run/kanidm-unixd.pid -T kanidm_unixd /usr/local/libexec/${name}"
procname=/usr/local/libexec/${name}
run_rc_command "$1"

View file

@ -0,0 +1,27 @@
#!/bin/sh
# PROVIDE: kanidm_unixd_tasks
# REQUIRE: LOGIN
# KEYWORD: shutdown
#
# Add these lines to /etc/rc.conf.local or /etc/rc.conf
# to enable this service:
#
# kanidm_unixd_tasks_enable (bool): Set to NO by default.
# Set it to YES to enable kanidm_unixd_tasks.
. /etc/rc.subr
name=kanidm_unixd_tasks
rcvar=kanidm_unixd_tasks_enable
load_rc_config $name
: ${kanidm_unixd_tasks_enable:="NO"}
pidfile="/var/run/kanidm-unixd-tasks.pid"
command=/usr/sbin/daemon
command_args="-u root -p /var/run/kanidm-unixd-tasks.pid -T kanidm_unixd_tasks /usr/local/libexec/${name}"
procname=/usr/local/libexec/${name}
run_rc_command "$1"

View file

@ -0,0 +1 @@
Kanidm is a simple and secure identity provider and client for UNIX systems

View file

@ -0,0 +1,13 @@
bin/kanidm
bin/kanidm-unix
bin/kanidm_ssh_authorizedkeys
bin/kanidm_ssh_authorizedkeys_direct
lib/nss_kanidm.so.1
lib/libpam_kanidm.so
libexec/kanidm_unixd
libexec/kanidm_unixd_tasks
@dir %%ETCDIR%%
@dir /var/lib
@dir(_kanidm_unixd,_kanidm_unixd,750) /var/cache/kanidm-unixd
@dir(_kanidm_unixd,_kanidm_unixd,750) /var/lib/kanidm-unixd
@dir(_kanidm_unixd,_kanidm_unixd,755) /var/run/kanidm-unixd

View file

@ -12,7 +12,7 @@ Conflicts=nscd.service
[Service]
DynamicUser=yes
SupplementaryGroups=tss shadow
SupplementaryGroups=tss
UMask=0027
CacheDirectory=kanidm-unixd
RuntimeDirectory=kanidm-unixd

View file

@ -42,3 +42,6 @@ sshkeys = { workspace = true }
[dev-dependencies]
enum-iterator = { workspace = true }
serde_urlencoded = { workspace = true }
[build-dependencies]
kanidm_build_profiles = { workspace = true }

3
proto/build.rs Normal file
View file

@ -0,0 +1,3 @@
fn main() {
profiles::apply_profile();
}

View file

@ -22,6 +22,8 @@ pub enum Attribute {
AcpCreateClass,
AcpEnable,
AcpModifyClass,
AcpModifyPresentClass,
AcpModifyRemoveClass,
AcpModifyPresentAttr,
AcpModifyRemovedAttr,
AcpReceiver,
@ -53,6 +55,7 @@ pub enum Attribute {
DisplayName,
Dn,
Domain,
DomainAllowEasterEggs,
DomainDevelopmentTaint,
DomainDisplayName,
DomainLdapBasedn,
@ -79,6 +82,7 @@ pub enum Attribute {
IdVerificationEcKey,
Image,
Index,
Indexed,
IpaNtHash,
IpaSshPubKey,
JwsEs256PrivateKey,
@ -93,6 +97,7 @@ pub enum Attribute {
LdapEmailAddress,
/// An LDAP Compatible sshkeys virtual attribute
LdapKeys,
LdapMaxQueryableAttrs,
LegalName,
LimitSearchMaxResults,
LimitSearchMaxFilterTest,
@ -140,6 +145,9 @@ pub enum Attribute {
Refers,
Replicated,
Rs256PrivateKeyDer,
/// A set of scim schemas. This is similar to a kanidm class.
#[serde(rename = "schemas")]
ScimSchemas,
Scope,
SourceUuid,
Spn,
@ -249,6 +257,8 @@ impl Attribute {
Attribute::AcpCreateClass => ATTR_ACP_CREATE_CLASS,
Attribute::AcpEnable => ATTR_ACP_ENABLE,
Attribute::AcpModifyClass => ATTR_ACP_MODIFY_CLASS,
Attribute::AcpModifyPresentClass => ATTR_ACP_MODIFY_PRESENT_CLASS,
Attribute::AcpModifyRemoveClass => ATTR_ACP_MODIFY_REMOVE_CLASS,
Attribute::AcpModifyPresentAttr => ATTR_ACP_MODIFY_PRESENTATTR,
Attribute::AcpModifyRemovedAttr => ATTR_ACP_MODIFY_REMOVEDATTR,
Attribute::AcpReceiver => ATTR_ACP_RECEIVER,
@ -279,6 +289,7 @@ impl Attribute {
Attribute::DisplayName => ATTR_DISPLAYNAME,
Attribute::Dn => ATTR_DN,
Attribute::Domain => ATTR_DOMAIN,
Attribute::DomainAllowEasterEggs => ATTR_DOMAIN_ALLOW_EASTER_EGGS,
Attribute::DomainDevelopmentTaint => ATTR_DOMAIN_DEVELOPMENT_TAINT,
Attribute::DomainDisplayName => ATTR_DOMAIN_DISPLAY_NAME,
Attribute::DomainLdapBasedn => ATTR_DOMAIN_LDAP_BASEDN,
@ -305,6 +316,7 @@ impl Attribute {
Attribute::IdVerificationEcKey => ATTR_ID_VERIFICATION_ECKEY,
Attribute::Image => ATTR_IMAGE,
Attribute::Index => ATTR_INDEX,
Attribute::Indexed => ATTR_INDEXED,
Attribute::IpaNtHash => ATTR_IPANTHASH,
Attribute::IpaSshPubKey => ATTR_IPASSHPUBKEY,
Attribute::JwsEs256PrivateKey => ATTR_JWS_ES256_PRIVATE_KEY,
@ -317,6 +329,7 @@ impl Attribute {
Attribute::LdapAllowUnixPwBind => ATTR_LDAP_ALLOW_UNIX_PW_BIND,
Attribute::LdapEmailAddress => ATTR_LDAP_EMAIL_ADDRESS,
Attribute::LdapKeys => ATTR_LDAP_KEYS,
Attribute::LdapMaxQueryableAttrs => ATTR_LDAP_MAX_QUERYABLE_ATTRS,
Attribute::LdapSshPublicKey => ATTR_LDAP_SSHPUBLICKEY,
Attribute::LegalName => ATTR_LEGALNAME,
Attribute::LimitSearchMaxResults => ATTR_LIMIT_SEARCH_MAX_RESULTS,
@ -368,6 +381,7 @@ impl Attribute {
Attribute::Replicated => ATTR_REPLICATED,
Attribute::Rs256PrivateKeyDer => ATTR_RS256_PRIVATE_KEY_DER,
Attribute::Scope => ATTR_SCOPE,
Attribute::ScimSchemas => ATTR_SCIM_SCHEMAS,
Attribute::SourceUuid => ATTR_SOURCE_UUID,
Attribute::Spn => ATTR_SPN,
Attribute::SshPublicKey => ATTR_SSH_PUBLICKEY,
@ -430,6 +444,8 @@ impl Attribute {
ATTR_ACP_CREATE_CLASS => Attribute::AcpCreateClass,
ATTR_ACP_ENABLE => Attribute::AcpEnable,
ATTR_ACP_MODIFY_CLASS => Attribute::AcpModifyClass,
ATTR_ACP_MODIFY_PRESENT_CLASS => Attribute::AcpModifyPresentClass,
ATTR_ACP_MODIFY_REMOVE_CLASS => Attribute::AcpModifyRemoveClass,
ATTR_ACP_MODIFY_PRESENTATTR => Attribute::AcpModifyPresentAttr,
ATTR_ACP_MODIFY_REMOVEDATTR => Attribute::AcpModifyRemovedAttr,
ATTR_ACP_RECEIVER => Attribute::AcpReceiver,
@ -460,6 +476,7 @@ impl Attribute {
ATTR_DISPLAYNAME => Attribute::DisplayName,
ATTR_DN => Attribute::Dn,
ATTR_DOMAIN => Attribute::Domain,
ATTR_DOMAIN_ALLOW_EASTER_EGGS => Attribute::DomainAllowEasterEggs,
ATTR_DOMAIN_DISPLAY_NAME => Attribute::DomainDisplayName,
ATTR_DOMAIN_DEVELOPMENT_TAINT => Attribute::DomainDevelopmentTaint,
ATTR_DOMAIN_LDAP_BASEDN => Attribute::DomainLdapBasedn,
@ -486,6 +503,7 @@ impl Attribute {
ATTR_ID_VERIFICATION_ECKEY => Attribute::IdVerificationEcKey,
ATTR_IMAGE => Attribute::Image,
ATTR_INDEX => Attribute::Index,
ATTR_INDEXED => Attribute::Indexed,
ATTR_IPANTHASH => Attribute::IpaNtHash,
ATTR_IPASSHPUBKEY => Attribute::IpaSshPubKey,
ATTR_JWS_ES256_PRIVATE_KEY => Attribute::JwsEs256PrivateKey,
@ -498,6 +516,7 @@ impl Attribute {
ATTR_LDAP_ALLOW_UNIX_PW_BIND => Attribute::LdapAllowUnixPwBind,
ATTR_LDAP_EMAIL_ADDRESS => Attribute::LdapEmailAddress,
ATTR_LDAP_KEYS => Attribute::LdapKeys,
ATTR_LDAP_MAX_QUERYABLE_ATTRS => Attribute::LdapMaxQueryableAttrs,
ATTR_SSH_PUBLICKEY => Attribute::SshPublicKey,
ATTR_LEGALNAME => Attribute::LegalName,
ATTR_LINKEDGROUP => Attribute::LinkedGroup,
@ -548,6 +567,7 @@ impl Attribute {
ATTR_REFERS => Attribute::Refers,
ATTR_REPLICATED => Attribute::Replicated,
ATTR_RS256_PRIVATE_KEY_DER => Attribute::Rs256PrivateKeyDer,
ATTR_SCIM_SCHEMAS => Attribute::ScimSchemas,
ATTR_SCOPE => Attribute::Scope,
ATTR_SOURCE_UUID => Attribute::SourceUuid,
ATTR_SPN => Attribute::Spn,
@ -620,6 +640,71 @@ impl From<Attribute> for String {
}
}
/// Sub attributes are a component of SCIM, allowing tagged sub properties of a complex
/// attribute to be accessed.
#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash)]
#[serde(rename_all = "lowercase", try_from = "&str", into = "AttrString")]
pub enum SubAttribute {
/// Denotes a primary value.
Primary,
#[cfg(not(test))]
Custom(AttrString),
}
impl From<SubAttribute> for AttrString {
fn from(val: SubAttribute) -> Self {
AttrString::from(val.as_str())
}
}
impl From<&str> for SubAttribute {
fn from(value: &str) -> Self {
Self::inner_from_str(value)
}
}
impl FromStr for SubAttribute {
type Err = Infallible;
fn from_str(value: &str) -> Result<Self, Self::Err> {
Ok(Self::inner_from_str(value))
}
}
impl SubAttribute {
pub fn as_str(&self) -> &str {
match self {
SubAttribute::Primary => SUB_ATTR_PRIMARY,
#[cfg(not(test))]
SubAttribute::Custom(s) => s,
}
}
// We allow this because the standard lib from_str is fallible, and we want an infallible version.
#[allow(clippy::should_implement_trait)]
fn inner_from_str(value: &str) -> Self {
// Could this be something like heapless to save allocations? Also gives a way
// to limit length of str?
match value.to_lowercase().as_str() {
SUB_ATTR_PRIMARY => SubAttribute::Primary,
#[cfg(not(test))]
_ => SubAttribute::Custom(AttrString::from(value)),
// Allowed only in tests
#[allow(clippy::unreachable)]
#[cfg(test)]
_ => {
unreachable!(
"Check that you've implemented the SubAttribute conversion for {:?}",
value
);
}
}
}
}
#[cfg(test)]
mod test {
use super::Attribute;

View file

@ -30,7 +30,7 @@ pub const VALID_IMAGE_UPLOAD_CONTENT_TYPES: [&str; 5] = [
pub const APPLICATION_JSON: &str = "application/json";
/// The "system" path for Kanidm client config
pub const DEFAULT_CLIENT_CONFIG_PATH: &str = "/etc/kanidm/config";
pub const DEFAULT_CLIENT_CONFIG_PATH: &str = env!("KANIDM_CLIENT_CONFIG_PATH");
/// The user-owned path for Kanidm client config
pub const DEFAULT_CLIENT_CONFIG_PATH_HOME: &str = "~/.config/kanidm";
@ -39,6 +39,8 @@ pub const DEFAULT_SERVER_ADDRESS: &str = "127.0.0.1:8443";
pub const DEFAULT_SERVER_LOCALHOST: &str = "localhost:8443";
/// The default LDAP bind address for the Kanidm client
pub const DEFAULT_LDAP_LOCALHOST: &str = "localhost:636";
/// The default amount of attributes that can be queried in LDAP
pub const DEFAULT_LDAP_MAXIMUM_QUERYABLE_ATTRIBUTES: usize = 16;
/// Default replication configuration
pub const DEFAULT_REPLICATION_ADDRESS: &str = "127.0.0.1:8444";
pub const DEFAULT_REPLICATION_ORIGIN: &str = "repl://localhost:8444";
@ -60,6 +62,8 @@ pub const ATTR_ACP_CREATE_ATTR: &str = "acp_create_attr";
pub const ATTR_ACP_CREATE_CLASS: &str = "acp_create_class";
pub const ATTR_ACP_ENABLE: &str = "acp_enable";
pub const ATTR_ACP_MODIFY_CLASS: &str = "acp_modify_class";
pub const ATTR_ACP_MODIFY_PRESENT_CLASS: &str = "acp_modify_present_class";
pub const ATTR_ACP_MODIFY_REMOVE_CLASS: &str = "acp_modify_remove_class";
pub const ATTR_ACP_MODIFY_PRESENTATTR: &str = "acp_modify_presentattr";
pub const ATTR_ACP_MODIFY_REMOVEDATTR: &str = "acp_modify_removedattr";
pub const ATTR_ACP_RECEIVER_GROUP: &str = "acp_receiver_group";
@ -89,6 +93,7 @@ pub const ATTR_DESCRIPTION: &str = "description";
pub const ATTR_DIRECTMEMBEROF: &str = "directmemberof";
pub const ATTR_DISPLAYNAME: &str = "displayname";
pub const ATTR_DN: &str = "dn";
pub const ATTR_DOMAIN_ALLOW_EASTER_EGGS: &str = "domain_allow_easter_eggs";
pub const ATTR_DOMAIN_DEVELOPMENT_TAINT: &str = "domain_development_taint";
pub const ATTR_DOMAIN_DISPLAY_NAME: &str = "domain_display_name";
pub const ATTR_DOMAIN_LDAP_BASEDN: &str = "domain_ldap_basedn";
@ -101,6 +106,7 @@ pub const ATTR_DYNGROUP_FILTER: &str = "dyngroup_filter";
pub const ATTR_DYNGROUP: &str = "dyngroup";
pub const ATTR_DYNMEMBER: &str = "dynmember";
pub const ATTR_LDAP_EMAIL_ADDRESS: &str = "emailaddress";
pub const ATTR_LDAP_MAX_QUERYABLE_ATTRS: &str = "ldap_max_queryable_attrs";
pub const ATTR_EMAIL_ALTERNATIVE: &str = "emailalternative";
pub const ATTR_EMAIL_PRIMARY: &str = "emailprimary";
pub const ATTR_EMAIL: &str = "email";
@ -120,6 +126,7 @@ pub const ATTR_GROUP: &str = "group";
pub const ATTR_ID_VERIFICATION_ECKEY: &str = "id_verification_eckey";
pub const ATTR_IMAGE: &str = "image";
pub const ATTR_INDEX: &str = "index";
pub const ATTR_INDEXED: &str = "indexed";
pub const ATTR_IPANTHASH: &str = "ipanthash";
pub const ATTR_IPASSHPUBKEY: &str = "ipasshpubkey";
pub const ATTR_JWS_ES256_PRIVATE_KEY: &str = "jws_es256_private_key";
@ -179,6 +186,7 @@ pub const ATTR_RECYCLEDDIRECTMEMBEROF: &str = "recycled_directmemberof";
pub const ATTR_REFERS: &str = "refers";
pub const ATTR_REPLICATED: &str = "replicated";
pub const ATTR_RS256_PRIVATE_KEY_DER: &str = "rs256_private_key_der";
pub const ATTR_SCIM_SCHEMAS: &str = "schemas";
pub const ATTR_SCOPE: &str = "scope";
pub const ATTR_SELF: &str = "self";
pub const ATTR_SOURCE_UUID: &str = "source_uuid";
@ -215,8 +223,11 @@ pub const ATTR_VERSION: &str = "version";
pub const ATTR_WEBAUTHN_ATTESTATION_CA_LIST: &str = "webauthn_attestation_ca_list";
pub const ATTR_ALLOW_PRIMARY_CRED_FALLBACK: &str = "allow_primary_cred_fallback";
pub const SUB_ATTR_PRIMARY: &str = "primary";
pub const OAUTH2_SCOPE_EMAIL: &str = ATTR_EMAIL;
pub const OAUTH2_SCOPE_GROUPS: &str = "groups";
pub const OAUTH2_SCOPE_SSH_PUBLICKEYS: &str = "ssh_publickeys";
pub const OAUTH2_SCOPE_OPENID: &str = "openid";
pub const OAUTH2_SCOPE_READ: &str = "read";
pub const OAUTH2_SCOPE_SUPPLEMENT: &str = "supplement";

View file

@ -130,6 +130,7 @@ pub enum CURegState {
None,
TotpCheck(TotpSecret),
TotpTryAgain,
TotpNameTryAgain(String),
TotpInvalidSha1,
BackupCodes(Vec<String>),
Passkey(CreationChallengeResponse),
@ -160,6 +161,7 @@ pub enum CURegWarning {
AttestedResidentKeyRequired,
Unsatisfiable,
WebauthnAttestationUnsatisfiable,
WebauthnUserVerificationRequired,
}
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]

View file

@ -142,17 +142,32 @@ pub enum OperationError {
DatabaseLockAcquisitionTimeout,
// Specific internal errors.
AU0001InvalidState,
AU0002JwsSerialisation,
AU0003JwsSignature,
AU0004UserAuthTokenInvalid,
AU0005DelayedProcessFailure,
AU0006CredentialMayNotReauthenticate,
AU0007UserAuthTokenInvalid,
// Kanidm Generic Errors
KG001TaskTimeout,
KG002TaskCommFailure,
KG003CacheClearFailed,
// What about something like this for unique errors?
// Credential Update Errors
CU0001WebauthnAttestationNotTrusted,
CU0002WebauthnRegistrationError,
CU0003WebauthnUserNotVerified,
// The session is inconsistent and can't be committed, but the errors
// can be resolved.
CU0004SessionInconsistent,
// Another session used this intent token, and so it can't be committed.
CU0005IntentTokenConflict,
// The intent token was invalidated before we could commit.
CU0006IntentTokenInvalidated,
// ValueSet errors
VS0001IncomingReplSshPublicKey,
VS0002CertificatePublicKeyDigest,
@ -173,6 +188,31 @@ pub enum OperationError {
// SCIM
SC0001IncomingSshPublicKey,
SC0002ReferenceSyntaxInvalid,
SC0003MailSyntaxInvalid,
SC0004UuidSyntaxInvalid,
SC0005BoolSyntaxInvalid,
SC0006Uint32SyntaxInvalid,
SC0007UrlSyntaxInvalid,
SC0008SyntaxTypeSyntaxInvalid,
SC0009IndexTypeSyntaxInvalid,
SC0010DateTimeSyntaxInvalid,
SC0011AddressSyntaxInvalid,
SC0012CertificateSyntaxInvalid,
SC0013CertificateInvalidDer,
SC0014CertificateInvalidDigest,
SC0015CredentialTypeSyntaxInvalid,
SC0016InameSyntaxInvalid,
SC0017Iutf8SyntaxInvalid,
SC0018NsUniqueIdSyntaxInvalid,
SC0019Oauth2ScopeSyntaxInvalid,
SC0020Oauth2ScopeMapSyntaxInvalid,
SC0021Oauth2ScopeMapMissingGroupIdentifier,
SC0022Oauth2ClaimMapSyntaxInvalid,
SC0023Oauth2ClaimMapMissingGroupIdentifier,
SC0024SshPublicKeySyntaxInvalid,
SC0025UiHintSyntaxInvalid,
SC0026Utf8SyntaxInvalid,
// Migration
MG0001InvalidReMigrationLevel,
MG0002RaiseDomainLevelExceedsMaximum,
@ -182,6 +222,7 @@ pub enum OperationError {
MG0006SKConstraintsNotMet,
MG0007Oauth2StrictConstraintsNotMet,
MG0008SkipUpgradeAttempted,
MG0009InvalidTargetLevelForBootstrap,
//
KP0001KeyProviderNotLoaded,
KP0002KeyProviderInvalidClass,
@ -235,6 +276,7 @@ pub enum OperationError {
// Web UI
UI0001ChallengeSerialisation,
UI0002InvalidState,
UI0003InvalidOauth2Resume,
// Unixd Things
KU001InitWhileSessionActive,
@ -271,7 +313,7 @@ impl Display for OperationError {
impl OperationError {
/// Return the message associated with the error if there is one.
fn message(&self) -> Option<String> {
pub fn message(&self) -> Option<String> {
match self {
Self::SessionExpired => None,
Self::EmptyRequest => None,
@ -337,9 +379,23 @@ impl OperationError {
Self::TransactionAlreadyCommitted => None,
Self::ValueDenyName => None,
Self::DatabaseLockAcquisitionTimeout => Some("Unable to acquire a database lock - the current server may be too busy. Try again later.".into()),
Self::AU0001InvalidState => Some("Invalid authentication session state for request".into()),
Self::AU0002JwsSerialisation => Some("JWS serialisation failed".into()),
Self::AU0003JwsSignature => Some("JWS signature failed".into()),
Self::AU0004UserAuthTokenInvalid => Some("User auth token was unable to be generated".into()),
Self::AU0005DelayedProcessFailure => Some("Delaying processing failure, unable to proceed".into()),
Self::AU0006CredentialMayNotReauthenticate => Some("Credential may not reauthenticate".into()),
Self::AU0007UserAuthTokenInvalid => Some("User auth token was unable to be generated".into()),
Self::CU0001WebauthnAttestationNotTrusted => None,
Self::CU0002WebauthnRegistrationError => None,
Self::CU0003WebauthnUserNotVerified => Some("User Verification bit not set while registering credential, you may need to configure a PIN on this device.".into()),
Self::CU0004SessionInconsistent => Some("The session is unable to be committed due to unresolved warnings.".into()),
Self::CU0005IntentTokenConflict => Some("The intent token used to create this session has been reused in another browser/tab and may not proceed.".into()),
Self::CU0006IntentTokenInvalidated => Some("The intent token has been invalidated/revoked before the commit could be accepted. Has it been used in another browser or tab?".into()),
Self::DB0001MismatchedRestoreVersion => None,
Self::DB0002MismatchedRestoreVersion => None,
Self::DB0003FilterResolveCacheBuild => None,
@ -407,10 +463,39 @@ impl OperationError {
Self::MG0006SKConstraintsNotMet => Some("Migration Constraints Not Met - Security Keys should not be present.".into()),
Self::MG0007Oauth2StrictConstraintsNotMet => Some("Migration Constraints Not Met - All OAuth2 clients must have strict-redirect-uri mode enabled.".into()),
Self::MG0008SkipUpgradeAttempted => Some("Skip Upgrade Attempted.".into()),
Self::MG0009InvalidTargetLevelForBootstrap => Some("The request target domain level was not valid for bootstrapping a new server instance".into()),
Self::PL0001GidOverlapsSystemRange => None,
Self::SC0001IncomingSshPublicKey => None,
Self::SC0002ReferenceSyntaxInvalid => Some("A SCIM Reference Set contained invalid syntax and can not be processed.".into()),
Self::SC0003MailSyntaxInvalid => Some("A SCIM Mail Address contained invalid syntax".into()),
Self::SC0004UuidSyntaxInvalid => Some("A SCIM Uuid contained invalid syntax".into()),
Self::SC0005BoolSyntaxInvalid => Some("A SCIM boolean contained invalid syntax".into()),
Self::SC0006Uint32SyntaxInvalid => Some("A SCIM Uint32 contained invalid syntax".into()),
Self::SC0007UrlSyntaxInvalid => Some("A SCIM Url contained invalid syntax".into()),
Self::SC0008SyntaxTypeSyntaxInvalid => Some("A SCIM SyntaxType contained invalid syntax".into()),
Self::SC0009IndexTypeSyntaxInvalid => Some("A SCIM IndexType contained invalid syntax".into()),
Self::SC0010DateTimeSyntaxInvalid => Some("A SCIM DateTime contained invalid syntax".into()),
Self::SC0011AddressSyntaxInvalid => Some("A SCIM Address contained invalid syntax".into()),
Self::SC0012CertificateSyntaxInvalid => Some("A SCIM Certificate contained invalid binary data".into()),
Self::SC0013CertificateInvalidDer => Some("A SCIM Certificate did not contain valid DER".into()),
Self::SC0014CertificateInvalidDigest => Some("A SCIM Certificate was unable to be digested".into()),
Self::SC0015CredentialTypeSyntaxInvalid => Some("A SCIM CredentialType contained invalid syntax".into()),
Self::SC0016InameSyntaxInvalid => Some("A SCIM Iname string contained invalid syntax".into()),
Self::SC0017Iutf8SyntaxInvalid => Some("A SCIM Iutf8 string contained invalid syntax".into()),
Self::SC0018NsUniqueIdSyntaxInvalid => Some("A SCIM NsUniqueID contained invalid syntax".into()),
Self::SC0019Oauth2ScopeSyntaxInvalid => Some("A SCIM Oauth2 Scope contained invalid syntax".into()),
Self::SC0020Oauth2ScopeMapSyntaxInvalid => Some("A SCIM Oauth2 Scope Map contained invalid syntax".into()),
Self::SC0021Oauth2ScopeMapMissingGroupIdentifier => Some("A SCIM Oauth2 Scope Map was missing a group name or uuid".into()),
Self::SC0022Oauth2ClaimMapSyntaxInvalid => Some("A SCIM Oauth2 Claim Map contained invalid syntax".into()),
Self::SC0023Oauth2ClaimMapMissingGroupIdentifier => Some("A SCIM Claim Map was missing a group name or uuid".into()),
Self::SC0024SshPublicKeySyntaxInvalid => Some("A SCIM Ssh Public Key contained invalid syntax".into()),
Self::SC0025UiHintSyntaxInvalid => Some("A SCIM UiHint contained invalid syntax".into()),
Self::SC0026Utf8SyntaxInvalid => Some("A SCIM Utf8 String Scope Map contained invalid syntax".into()),
Self::UI0001ChallengeSerialisation => Some("The WebAuthn challenge was unable to be serialised.".into()),
Self::UI0002InvalidState => Some("The credential update process returned an invalid state transition.".into()),
Self::UI0003InvalidOauth2Resume => Some("The server attemped to resume OAuth2, but no OAuth2 session is in progress.".into()),
Self::VL0001ValueSshPublicKeyString => None,
Self::VS0001IncomingReplSshPublicKey => None,
Self::VS0002CertificatePublicKeyDigest |

View file

@ -6,7 +6,10 @@ use base64::{engine::general_purpose::STANDARD, Engine as _};
use serde::{Deserialize, Serialize};
use serde_with::base64::{Base64, UrlSafe};
use serde_with::formats::SpaceSeparator;
use serde_with::{formats, serde_as, skip_serializing_none, StringWithSeparator};
use serde_with::{
formats, rust::deserialize_ignore_any, serde_as, skip_serializing_none, NoneAsEmptyString,
StringWithSeparator,
};
use url::Url;
use uuid::Uuid;
@ -33,26 +36,73 @@ pub struct PkceRequest {
/// An OAuth2 client redirects to the authorisation server with Authorisation Request
/// parameters.
#[serde_as]
#[skip_serializing_none]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct AuthorisationRequest {
// Must be "code". (or token, see 4.2.1)
pub response_type: String,
pub response_type: ResponseType,
/// Response mode.
///
/// Optional; defaults to `query` for `response_type=code` (Auth Code), and
/// `fragment` for `response_type=token` (Implicit Grant, which we probably
/// won't support).
///
/// Reference:
/// [OAuth 2.0 Multiple Response Type Encoding Practices: Response Modes](https://openid.net/specs/oauth-v2-multiple-response-types-1_0.html#ResponseModes)
pub response_mode: Option<ResponseMode>,
pub client_id: String,
pub state: String,
#[serde_as(as = "NoneAsEmptyString")]
pub state: Option<String>,
#[serde(flatten)]
pub pkce_request: Option<PkceRequest>,
pub redirect_uri: Url,
pub scope: String,
#[serde_as(as = "StringWithSeparator::<SpaceSeparator, String>")]
pub scope: BTreeSet<String>,
// OIDC adds a nonce parameter that is optional.
pub nonce: Option<String>,
// OIDC also allows other optional params
#[serde(flatten)]
pub oidc_ext: AuthorisationRequestOidc,
// Needs to be hoisted here due to serde flatten bug #3185
pub max_age: Option<i64>,
#[serde(flatten)]
pub unknown_keys: BTreeMap<String, serde_json::value::Value>,
}
impl AuthorisationRequest {
/// Get the `response_mode` appropriate for this request, taking into
/// account defaults from the `response_type` parameter.
///
/// Returns `None` if the selection is invalid.
///
/// Reference:
/// [OAuth 2.0 Multiple Response Type Encoding Practices: Response Modes](https://openid.net/specs/oauth-v2-multiple-response-types-1_0.html#ResponseModes)
pub const fn get_response_mode(&self) -> Option<ResponseMode> {
match (self.response_mode, self.response_type) {
// https://openid.net/specs/oauth-v2-multiple-response-types-1_0.html#id_token
// The default Response Mode for this Response Type is the fragment
// encoding and the query encoding MUST NOT be used.
(None, ResponseType::IdToken) => Some(ResponseMode::Fragment),
(Some(ResponseMode::Query), ResponseType::IdToken) => None,
// https://datatracker.ietf.org/doc/html/rfc6749#section-4.1.2
(None, ResponseType::Code) => Some(ResponseMode::Query),
// https://datatracker.ietf.org/doc/html/rfc6749#section-4.2.2
(None, ResponseType::Token) => Some(ResponseMode::Fragment),
// https://openid.net/specs/oauth-v2-multiple-response-types-1_0.html#Security
// In no case should a set of Authorization Response parameters
// whose default Response Mode is the fragment encoding be encoded
// using the query encoding.
(Some(ResponseMode::Query), ResponseType::Token) => None,
// Allow others.
(Some(m), _) => Some(m),
}
}
}
/// An OIDC client redirects to the authorisation server with Authorisation Request
/// parameters.
#[skip_serializing_none]
@ -60,7 +110,6 @@ pub struct AuthorisationRequest {
pub struct AuthorisationRequestOidc {
pub display: Option<String>,
pub prompt: Option<String>,
pub max_age: Option<i64>,
pub ui_locales: Option<()>,
pub claims_locales: Option<()>,
pub id_token_hint: Option<String>,
@ -184,6 +233,7 @@ pub struct OAuth2RFC9068TokenExtensions {
}
/// The response for an access token
#[serde_as]
#[skip_serializing_none]
#[derive(Serialize, Deserialize, Debug)]
pub struct AccessTokenResponse {
@ -194,7 +244,8 @@ pub struct AccessTokenResponse {
pub refresh_token: Option<String>,
/// Space separated list of scopes that were approved, if this differs from the
/// original request.
pub scope: Option<String>,
#[serde_as(as = "StringWithSeparator::<SpaceSeparator, String>")]
pub scope: BTreeSet<String>,
/// If the `openid` scope was requested, an `id_token` may be present in the response.
pub id_token: Option<String>,
}
@ -247,11 +298,13 @@ pub struct AccessTokenIntrospectRequest {
/// Response to an introspection request. If the token is inactive or revoked, only
/// `active` will be set to the value of `false`.
#[serde_as]
#[skip_serializing_none]
#[derive(Serialize, Deserialize, Debug)]
pub struct AccessTokenIntrospectResponse {
pub active: bool,
pub scope: Option<String>,
#[serde_as(as = "StringWithSeparator::<SpaceSeparator, String>")]
pub scope: BTreeSet<String>,
pub client_id: Option<String>,
pub username: Option<String>,
pub token_type: Option<AccessTokenType>,
@ -268,7 +321,7 @@ impl AccessTokenIntrospectResponse {
pub fn inactive() -> Self {
AccessTokenIntrospectResponse {
active: false,
scope: None,
scope: BTreeSet::default(),
client_id: None,
username: None,
token_type: None,
@ -283,19 +336,27 @@ impl AccessTokenIntrospectResponse {
}
}
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
#[derive(Clone, Copy, Serialize, Deserialize, Debug, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum ResponseType {
// Auth Code flow
// https://datatracker.ietf.org/doc/html/rfc6749#section-4.1.1
Code,
// Implicit Grant flow
// https://datatracker.ietf.org/doc/html/rfc6749#section-4.2.1
Token,
// https://openid.net/specs/oauth-v2-multiple-response-types-1_0.html#id_token
IdToken,
}
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
#[derive(Clone, Copy, Serialize, Deserialize, Debug, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum ResponseMode {
Query,
Fragment,
FormPost,
#[serde(other, deserialize_with = "deserialize_ignore_any")]
Invalid,
}
fn response_modes_supported_default() -> Vec<ResponseMode> {
@ -386,6 +447,21 @@ fn require_request_uri_parameter_supported_default() -> bool {
false
}
#[derive(Serialize, Deserialize, Debug)]
pub struct OidcWebfingerRel {
pub rel: String,
pub href: String,
}
/// The response to an Webfinger request. Only a subset of the body is defined here.
/// <https://datatracker.ietf.org/doc/html/rfc7033#section-4.4>
#[skip_serializing_none]
#[derive(Serialize, Deserialize, Debug)]
pub struct OidcWebfingerResponse {
pub subject: String,
pub links: Vec<OidcWebfingerRel>,
}
/// The response to an OpenID connect discovery request
/// <https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderMetadata>
#[skip_serializing_none]

View file

@ -1,11 +1,192 @@
//! These are types that a client will send to the server.
use super::ScimEntryGetQuery;
use super::ScimOauth2ClaimMapJoinChar;
use crate::attribute::{Attribute, SubAttribute};
use serde::{Deserialize, Serialize};
use serde_json::Value as JsonValue;
use serde_with::formats::PreferMany;
use serde_with::OneOrMany;
use serde_with::{base64, formats, serde_as, skip_serializing_none};
use sshkey_attest::proto::PublicKey as SshPublicKey;
use std::collections::{BTreeMap, BTreeSet};
use time::format_description::well_known::Rfc3339;
use time::OffsetDateTime;
use uuid::Uuid;
pub type ScimSshPublicKeys = Vec<ScimSshPublicKey>;
#[derive(Deserialize, Serialize, Debug, Clone)]
#[serde(rename_all = "camelCase")]
#[serde(deny_unknown_fields, rename_all = "camelCase")]
pub struct ScimSshPublicKey {
pub label: String,
pub value: SshPublicKey,
}
#[serde_as]
#[skip_serializing_none]
#[derive(Deserialize, Serialize, Debug, Clone)]
#[serde(deny_unknown_fields, rename_all = "camelCase")]
pub struct ScimReference {
pub uuid: Option<Uuid>,
pub value: Option<String>,
}
pub type ScimReferences = Vec<ScimReference>;
#[serde_as]
#[derive(Deserialize, Serialize, Debug, Clone, PartialEq, Eq)]
#[serde(transparent)]
pub struct ScimDateTime {
#[serde_as(as = "Rfc3339")]
pub date_time: OffsetDateTime,
}
#[serde_as]
#[derive(Deserialize, Serialize, Debug, Clone, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct ScimCertificate {
#[serde_as(as = "base64::Base64<base64::UrlSafe, formats::Unpadded>")]
pub der: Vec<u8>,
}
#[derive(Deserialize, Serialize, Debug, Clone, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct ScimAddress {
pub street_address: String,
pub locality: String,
pub region: String,
pub postal_code: String,
pub country: String,
}
#[serde_as]
#[derive(Deserialize, Serialize, Debug, Clone)]
#[serde(rename_all = "camelCase")]
pub struct ScimOAuth2ClaimMap {
pub group: Option<String>,
pub group_uuid: Option<Uuid>,
pub claim: String,
pub join_char: ScimOauth2ClaimMapJoinChar,
pub values: BTreeSet<String>,
}
#[serde_as]
#[derive(Deserialize, Serialize, Debug, Clone)]
#[serde(rename_all = "camelCase")]
pub struct ScimOAuth2ScopeMap {
pub group: Option<String>,
pub group_uuid: Option<Uuid>,
pub scopes: BTreeSet<String>,
}
#[derive(Serialize, Debug, Clone)]
pub struct ScimEntryPutKanidm {
pub id: Uuid,
#[serde(flatten)]
pub attrs: BTreeMap<Attribute, Option<super::server::ScimValueKanidm>>,
}
#[serde_as]
#[derive(Deserialize, Serialize, Debug, Clone)]
pub struct ScimStrings(#[serde_as(as = "OneOrMany<_, PreferMany>")] pub Vec<String>);
#[derive(Debug, Clone, Deserialize, Default)]
pub struct ScimEntryPutGeneric {
// id is only used to target the entry in question
pub id: Uuid,
#[serde(flatten)]
/// Non-standard extension - allow query options to be set in a put request. This
/// is because a put request also returns the entry state post put, so we want
/// to allow putters to adjust and control what is returned here.
pub query: ScimEntryGetQuery,
// external_id can't be set by put
// meta is skipped on put
// Schemas are decoded as part of "attrs".
/// Update an attribute to contain the following value state.
/// If the attribute is None, it is removed.
#[serde(flatten)]
pub attrs: BTreeMap<Attribute, Option<JsonValue>>,
}
impl TryFrom<ScimEntryPutKanidm> for ScimEntryPutGeneric {
type Error = serde_json::Error;
fn try_from(value: ScimEntryPutKanidm) -> Result<Self, Self::Error> {
let ScimEntryPutKanidm { id, attrs } = value;
let attrs = attrs
.into_iter()
.map(|(attr, value)| {
if let Some(v) = value {
serde_json::to_value(v).map(|json_value| (attr, Some(json_value)))
} else {
Ok((attr, None))
}
})
.collect::<Result<_, _>>()?;
Ok(ScimEntryPutGeneric {
id,
attrs,
query: Default::default(),
})
}
}
#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
pub struct AttrPath {
pub a: Attribute,
pub s: Option<SubAttribute>,
}
impl From<Attribute> for AttrPath {
fn from(a: Attribute) -> Self {
Self { a, s: None }
}
}
impl From<(Attribute, SubAttribute)> for AttrPath {
fn from((a, s): (Attribute, SubAttribute)) -> Self {
Self { a, s: Some(s) }
}
}
#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
pub enum ScimFilter {
Or(Box<ScimFilter>, Box<ScimFilter>),
And(Box<ScimFilter>, Box<ScimFilter>),
Not(Box<ScimFilter>),
Present(AttrPath),
Equal(AttrPath, JsonValue),
NotEqual(AttrPath, JsonValue),
Contains(AttrPath, JsonValue),
StartsWith(AttrPath, JsonValue),
EndsWith(AttrPath, JsonValue),
Greater(AttrPath, JsonValue),
Less(AttrPath, JsonValue),
GreaterOrEqual(AttrPath, JsonValue),
LessOrEqual(AttrPath, JsonValue),
Complex(Attribute, Box<ScimComplexFilter>),
}
#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
pub enum ScimComplexFilter {
Or(Box<ScimComplexFilter>, Box<ScimComplexFilter>),
And(Box<ScimComplexFilter>, Box<ScimComplexFilter>),
Not(Box<ScimComplexFilter>),
Present(SubAttribute),
Equal(SubAttribute, JsonValue),
NotEqual(SubAttribute, JsonValue),
Contains(SubAttribute, JsonValue),
StartsWith(SubAttribute, JsonValue),
EndsWith(SubAttribute, JsonValue),
Greater(SubAttribute, JsonValue),
Less(SubAttribute, JsonValue),
GreaterOrEqual(SubAttribute, JsonValue),
LessOrEqual(SubAttribute, JsonValue),
}

View file

@ -11,15 +11,16 @@
//! The [scim_proto] library, which is generic over all scim implementations.
//!
//! The client module, which describes how a client should transmit entries, and
//! how it should parse them when it recieves them.
//! how it should parse them when it receives them.
//!
//! The server module, which describes how a server should transmit entries and
//! how it should recieve them.
//! how it should receive them.
use crate::attribute::Attribute;
use serde::{Deserialize, Serialize};
use serde_json::Value as JsonValue;
use sshkey_attest::proto::PublicKey as SshPublicKey;
use std::collections::BTreeMap;
use std::ops::Not;
use utoipa::ToSchema;
use serde_with::formats::CommaSeparator;
@ -27,6 +28,7 @@ use serde_with::{serde_as, skip_serializing_none, StringWithSeparator};
pub use self::synch::*;
pub use scim_proto::prelude::*;
pub use serde_json::Value as JsonValue;
pub mod client;
pub mod server;
@ -46,10 +48,52 @@ pub struct ScimEntryGeneric {
/// SCIM Query Parameters used during the get of a single entry
#[serde_as]
#[skip_serializing_none]
#[derive(Serialize, Deserialize, Debug, Default)]
#[derive(Serialize, Deserialize, Clone, Debug, Default)]
pub struct ScimEntryGetQuery {
#[serde_as(as = "Option<StringWithSeparator::<CommaSeparator, Attribute>>")]
pub attributes: Option<Vec<Attribute>>,
#[serde(default, skip_serializing_if = "<&bool>::not")]
pub ext_access_check: bool,
}
#[derive(Serialize, Deserialize, Debug, Clone, ToSchema)]
pub enum ScimSchema {
#[serde(rename = "urn:ietf:params:scim:schemas:kanidm:sync:1:account")]
SyncAccountV1,
#[serde(rename = "urn:ietf:params:scim:schemas:kanidm:sync:1:group")]
SyncV1GroupV1,
#[serde(rename = "urn:ietf:params:scim:schemas:kanidm:sync:1:person")]
SyncV1PersonV1,
#[serde(rename = "urn:ietf:params:scim:schemas:kanidm:sync:1:posixaccount")]
SyncV1PosixAccountV1,
#[serde(rename = "urn:ietf:params:scim:schemas:kanidm:sync:1:posixgroup")]
SyncV1PosixGroupV1,
}
#[serde_as]
#[derive(Deserialize, Serialize, Debug, Clone, ToSchema)]
#[serde(deny_unknown_fields, rename_all = "camelCase")]
pub struct ScimMail {
#[serde(default)]
pub primary: bool,
pub value: String,
}
#[derive(Deserialize, Serialize, Debug, Clone, ToSchema)]
#[serde(rename_all = "camelCase")]
pub struct ScimSshPublicKey {
pub label: String,
pub value: SshPublicKey,
}
#[derive(Deserialize, Serialize, Debug, Clone, ToSchema)]
pub enum ScimOauth2ClaimMapJoinChar {
#[serde(rename = ",", alias = "csv")]
CommaSeparatedValue,
#[serde(rename = " ", alias = "ssv")]
SpaceSeparatedValue,
#[serde(rename = ";", alias = "json_array")]
JsonArray,
}
#[cfg(test)]
@ -79,12 +123,15 @@ mod tests {
// Group
let group_uuid = uuid::uuid!("2d0a9e7c-cc08-4ca2-8d7f-114f9abcfc8a");
let group = ScimSyncGroup::builder("testgroup".to_string(), group_uuid)
.set_description(Some("test desc".to_string()))
.set_gidnumber(Some(12345))
.set_members(vec!["member_a".to_string(), "member_a".to_string()].into_iter())
.set_external_id(Some("cn=testgroup".to_string()))
.build();
let group = ScimSyncGroup::builder(
group_uuid,
"cn=testgroup".to_string(),
"testgroup".to_string(),
)
.set_description(Some("test desc".to_string()))
.set_gidnumber(Some(12345))
.set_members(vec!["member_a".to_string(), "member_a".to_string()].into_iter())
.build();
let entry: Result<ScimEntry, _> = group.try_into();
@ -95,32 +142,35 @@ mod tests {
let user_sshkey = "sk-ecdsa-sha2-nistp256@openssh.com AAAAInNrLWVjZHNhLXNoYTItbmlzdHAyNTZAb3BlbnNzaC5jb20AAAAIbmlzdHAyNTYAAABBBENubZikrb8hu+HeVRdZ0pp/VAk2qv4JDbuJhvD0yNdWDL2e3cBbERiDeNPkWx58Q4rVnxkbV1fa8E2waRtT91wAAAAEc3NoOg== testuser@fidokey";
let person =
ScimSyncPerson::builder(user_uuid, "testuser".to_string(), "Test User".to_string())
.set_password_import(Some("new_password".to_string()))
.set_unix_password_import(Some("new_password".to_string()))
.set_totp_import(vec![ScimTotp {
external_id: "Totp".to_string(),
secret: "abcd".to_string(),
algo: "SHA3".to_string(),
step: 60,
digits: 8,
}])
.set_mail(vec![MultiValueAttr {
primary: Some(true),
value: "testuser@example.com".to_string(),
..Default::default()
}])
.set_ssh_publickey(vec![ScimSshPubKey {
label: "Key McKeyface".to_string(),
value: user_sshkey.to_string(),
}])
.set_login_shell(Some("/bin/false".to_string()))
.set_account_valid_from(Some("2023-11-28T04:57:55Z".to_string()))
.set_account_expire(Some("2023-11-28T04:57:55Z".to_string()))
.set_gidnumber(Some(54321))
.set_external_id(Some("cn=testuser".to_string()))
.build();
let person = ScimSyncPerson::builder(
user_uuid,
"cn=testuser".to_string(),
"testuser".to_string(),
"Test User".to_string(),
)
.set_password_import(Some("new_password".to_string()))
.set_unix_password_import(Some("new_password".to_string()))
.set_totp_import(vec![ScimTotp {
external_id: "Totp".to_string(),
secret: "abcd".to_string(),
algo: "SHA3".to_string(),
step: 60,
digits: 8,
}])
.set_mail(vec![MultiValueAttr {
primary: Some(true),
value: "testuser@example.com".to_string(),
..Default::default()
}])
.set_ssh_publickey(vec![ScimSshPubKey {
label: "Key McKeyface".to_string(),
value: user_sshkey.to_string(),
}])
.set_login_shell(Some("/bin/false".to_string()))
.set_account_valid_from(Some("2023-11-28T04:57:55Z".to_string()))
.set_account_expire(Some("2023-11-28T04:57:55Z".to_string()))
.set_gidnumber(Some(54321))
.build();
let entry: Result<ScimEntry, _> = person.try_into();
@ -131,7 +181,10 @@ mod tests {
fn scim_entry_get_query() {
use super::*;
let q = ScimEntryGetQuery { attributes: None };
let q = ScimEntryGetQuery {
attributes: None,
..Default::default()
};
let txt = serde_urlencoded::to_string(&q).unwrap();
@ -139,6 +192,7 @@ mod tests {
let q = ScimEntryGetQuery {
attributes: Some(vec![Attribute::Name]),
ext_access_check: false,
};
let txt = serde_urlencoded::to_string(&q).unwrap();
@ -146,9 +200,10 @@ mod tests {
let q = ScimEntryGetQuery {
attributes: Some(vec![Attribute::Name, Attribute::Spn]),
ext_access_check: true,
};
let txt = serde_urlencoded::to_string(&q).unwrap();
assert_eq!(txt, "attributes=name%2Cspn");
assert_eq!(txt, "attributes=name%2Cspn&ext_access_check=true");
}
}

View file

@ -1,8 +1,11 @@
use super::ScimMail;
use super::ScimOauth2ClaimMapJoinChar;
use super::ScimSshPublicKey;
use crate::attribute::Attribute;
use crate::internal::UiHint;
use scim_proto::ScimEntryHeader;
use serde::Serialize;
use serde_with::{base64, formats, hex::Hex, serde_as, skip_serializing_none, StringWithSeparator};
use sshkey_attest::proto::PublicKey as SshPublicKey;
use serde_with::{base64, formats, hex::Hex, serde_as, skip_serializing_none};
use std::collections::{BTreeMap, BTreeSet};
use time::format_description::well_known::Rfc3339;
use time::OffsetDateTime;
@ -13,14 +16,54 @@ use uuid::Uuid;
/// A strongly typed ScimEntry that is for transmission to clients. This uses
/// Kanidm internal strong types for values allowing direct serialisation and
/// transmission.
#[serde_as]
#[skip_serializing_none]
#[derive(Serialize, Debug, Clone, ToSchema)]
pub struct ScimEntryKanidm {
#[serde(flatten)]
pub header: ScimEntryHeader,
pub ext_access_check: Option<ScimEffectiveAccess>,
#[serde(flatten)]
pub attrs: BTreeMap<Attribute, ScimValueKanidm>,
}
#[derive(Serialize, Debug, Clone, ToSchema)]
pub enum ScimAttributeEffectiveAccess {
/// All attributes on the entry have this permission granted
Grant,
/// All attributes on the entry have this permission denied
Deny,
/// The following attributes on the entry have this permission granted
Allow(BTreeSet<Attribute>),
}
impl ScimAttributeEffectiveAccess {
/// Check if the effective access allows or denies this attribute
pub fn check(&self, attr: &Attribute) -> bool {
match self {
Self::Grant => true,
Self::Deny => false,
Self::Allow(set) => set.contains(attr),
}
}
}
#[derive(Serialize, Debug, Clone, ToSchema)]
#[serde(rename_all = "camelCase")]
pub struct ScimEffectiveAccess {
/// The identity that inherits the effective permission
pub ident: Uuid,
/// If the ident may delete the target entry
pub delete: bool,
/// The set of effective access over search events
pub search: ScimAttributeEffectiveAccess,
/// The set of effective access over modify present events
pub modify_present: ScimAttributeEffectiveAccess,
/// The set of effective access over modify remove events
pub modify_remove: ScimAttributeEffectiveAccess,
}
#[derive(Serialize, Debug, Clone, ToSchema)]
#[serde(rename_all = "camelCase")]
pub struct ScimAddress {
@ -32,13 +75,6 @@ pub struct ScimAddress {
pub country: String,
}
#[derive(Serialize, Debug, Clone, ToSchema)]
#[serde(rename_all = "camelCase")]
pub struct ScimMail {
pub primary: bool,
pub value: String,
}
#[derive(Serialize, Debug, Clone, ToSchema)]
#[serde(rename_all = "camelCase")]
pub struct ScimApplicationPassword {
@ -75,13 +111,6 @@ pub struct ScimAuditString {
pub value: String,
}
#[derive(Serialize, Debug, Clone, ToSchema)]
#[serde(rename_all = "camelCase")]
pub struct ScimSshPublicKey {
pub label: String,
pub value: SshPublicKey,
}
#[derive(Serialize, Debug, Clone, ToSchema)]
#[serde(rename_all = "camelCase")]
pub enum ScimIntentTokenState {
@ -164,8 +193,8 @@ pub struct ScimApiToken {
#[derive(Serialize, Debug, Clone, ToSchema)]
#[serde(rename_all = "camelCase")]
pub struct ScimOAuth2ScopeMap {
pub uuid: Uuid,
#[serde_as(as = "StringWithSeparator::<formats::SpaceSeparator, String>")]
pub group: String,
pub group_uuid: Uuid,
pub scopes: BTreeSet<String>,
}
@ -173,14 +202,13 @@ pub struct ScimOAuth2ScopeMap {
#[derive(Serialize, Debug, Clone, ToSchema)]
#[serde(rename_all = "camelCase")]
pub struct ScimOAuth2ClaimMap {
pub group: Uuid,
pub group: String,
pub group_uuid: Uuid,
pub claim: String,
pub join_char: String,
#[serde_as(as = "StringWithSeparator::<formats::SpaceSeparator, String>")]
pub join_char: ScimOauth2ClaimMapJoinChar,
pub values: BTreeSet<String>,
}
#[serde_as]
#[derive(Serialize, Debug, Clone, PartialEq, Eq, ToSchema)]
#[serde(rename_all = "camelCase")]
pub struct ScimReference {
@ -226,6 +254,99 @@ pub enum ScimValueKanidm {
OAuth2ScopeMap(Vec<ScimOAuth2ScopeMap>),
OAuth2ClaimMap(Vec<ScimOAuth2ClaimMap>),
KeyInternal(Vec<ScimKeyInternal>),
UiHints(Vec<UiHint>),
}
#[serde_as]
#[derive(Serialize, Debug, Clone, ToSchema)]
pub struct ScimPerson {
pub uuid: Uuid,
pub name: String,
pub displayname: String,
pub spn: String,
pub description: Option<String>,
pub mails: Vec<ScimMail>,
pub managed_by: Option<ScimReference>,
pub groups: Vec<ScimReference>,
}
impl TryFrom<ScimEntryKanidm> for ScimPerson {
type Error = ();
fn try_from(scim_entry: ScimEntryKanidm) -> Result<Self, Self::Error> {
let uuid = scim_entry.header.id;
let name = scim_entry
.attrs
.get(&Attribute::Name)
.and_then(|v| match v {
ScimValueKanidm::String(s) => Some(s.clone()),
_ => None,
})
.ok_or(())?;
let displayname = scim_entry
.attrs
.get(&Attribute::DisplayName)
.and_then(|v| match v {
ScimValueKanidm::String(s) => Some(s.clone()),
_ => None,
})
.ok_or(())?;
let spn = scim_entry
.attrs
.get(&Attribute::Spn)
.and_then(|v| match v {
ScimValueKanidm::String(s) => Some(s.clone()),
_ => None,
})
.ok_or(())?;
let description = scim_entry
.attrs
.get(&Attribute::Description)
.and_then(|v| match v {
ScimValueKanidm::String(s) => Some(s.clone()),
_ => None,
});
let mails = scim_entry
.attrs
.get(&Attribute::Mail)
.and_then(|v| match v {
ScimValueKanidm::Mail(m) => Some(m.clone()),
_ => None,
})
.unwrap_or_default();
let groups = scim_entry
.attrs
.get(&Attribute::DirectMemberOf)
.and_then(|v| match v {
ScimValueKanidm::EntryReferences(v) => Some(v.clone()),
_ => None,
})
.unwrap_or_default();
let managed_by = scim_entry
.attrs
.get(&Attribute::EntryManagedBy)
.and_then(|v| match v {
ScimValueKanidm::EntryReference(v) => Some(v.clone()),
_ => None,
});
Ok(ScimPerson {
uuid,
name,
displayname,
spn,
description,
mails,
managed_by,
groups,
})
}
}
impl From<bool> for ScimValueKanidm {
@ -240,6 +361,12 @@ impl From<OffsetDateTime> for ScimValueKanidm {
}
}
impl From<Vec<UiHint>> for ScimValueKanidm {
fn from(set: Vec<UiHint>) -> Self {
Self::UiHints(set)
}
}
impl From<Vec<OffsetDateTime>> for ScimValueKanidm {
fn from(set: Vec<OffsetDateTime>) -> Self {
Self::ArrayDateTime(set)
@ -252,6 +379,12 @@ impl From<String> for ScimValueKanidm {
}
}
impl From<&str> for ScimValueKanidm {
fn from(s: &str) -> Self {
Self::String(s.to_string())
}
}
impl From<Vec<String>> for ScimValueKanidm {
fn from(set: Vec<String>) -> Self {
Self::ArrayString(set)

View file

@ -85,19 +85,19 @@ pub struct ScimSshPubKey {
#[skip_serializing_none]
#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(rename_all = "camelCase")]
#[serde(rename_all = "snake_case")]
pub struct ScimSyncPerson {
#[serde(flatten)]
pub entry: ScimEntryHeader,
pub user_name: String,
pub display_name: String,
pub name: String,
pub displayname: String,
pub gidnumber: Option<u32>,
pub password_import: Option<String>,
pub unix_password_import: Option<String>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub totp_import: Vec<ScimTotp>,
pub login_shell: Option<String>,
pub loginshell: Option<String>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub mail: Vec<MultiValueAttr>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
@ -119,7 +119,12 @@ pub struct ScimSyncPersonBuilder {
}
impl ScimSyncPerson {
pub fn builder(id: Uuid, user_name: String, display_name: String) -> ScimSyncPersonBuilder {
pub fn builder(
id: Uuid,
external_id: String,
name: String,
displayname: String,
) -> ScimSyncPersonBuilder {
ScimSyncPersonBuilder {
inner: ScimSyncPerson {
entry: ScimEntryHeader {
@ -128,16 +133,16 @@ impl ScimSyncPerson {
SCIM_SCHEMA_SYNC_PERSON.to_string(),
],
id,
external_id: None,
external_id: Some(external_id),
meta: None,
},
user_name,
display_name,
name,
displayname,
gidnumber: None,
password_import: None,
unix_password_import: None,
totp_import: Vec::with_capacity(0),
login_shell: None,
loginshell: None,
mail: Vec::with_capacity(0),
ssh_publickey: Vec::with_capacity(0),
account_valid_from: None,
@ -173,8 +178,8 @@ impl ScimSyncPersonBuilder {
self
}
pub fn set_login_shell(mut self, login_shell: Option<String>) -> Self {
self.inner.login_shell = login_shell;
pub fn set_login_shell(mut self, loginshell: Option<String>) -> Self {
self.inner.loginshell = loginshell;
self
}
@ -205,11 +210,6 @@ impl ScimSyncPersonBuilder {
self
}
pub fn set_external_id(mut self, external_id: Option<String>) -> Self {
self.inner.entry.external_id = external_id;
self
}
pub fn build(self) -> ScimSyncPerson {
self.inner
}
@ -220,8 +220,9 @@ pub struct ScimExternalMember {
pub external_id: String,
}
#[skip_serializing_none]
#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(rename_all = "camelCase")]
#[serde(rename_all = "snake_case")]
pub struct ScimSyncGroup {
#[serde(flatten)]
pub entry: ScimEntryHeader,
@ -229,7 +230,8 @@ pub struct ScimSyncGroup {
pub name: String,
pub description: Option<String>,
pub gidnumber: Option<u32>,
pub members: Vec<ScimExternalMember>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub member: Vec<ScimExternalMember>,
}
impl TryInto<ScimEntry> for ScimSyncGroup {
@ -247,19 +249,19 @@ pub struct ScimSyncGroupBuilder {
}
impl ScimSyncGroup {
pub fn builder(name: String, id: Uuid) -> ScimSyncGroupBuilder {
pub fn builder(id: Uuid, external_id: String, name: String) -> ScimSyncGroupBuilder {
ScimSyncGroupBuilder {
inner: ScimSyncGroup {
entry: ScimEntryHeader {
schemas: vec![SCIM_SCHEMA_SYNC_GROUP.to_string()],
id,
external_id: None,
external_id: Some(external_id),
meta: None,
},
name,
description: None,
gidnumber: None,
members: Vec::with_capacity(0),
member: Vec::with_capacity(0),
},
}
}
@ -288,17 +290,12 @@ impl ScimSyncGroupBuilder {
where
I: Iterator<Item = String>,
{
self.inner.members = member_iter
self.inner.member = member_iter
.map(|external_id| ScimExternalMember { external_id })
.collect();
self
}
pub fn set_external_id(mut self, external_id: Option<String>) -> Self {
self.inner.entry.external_id = external_id;
self
}
pub fn build(self) -> ScimSyncGroup {
self.inner
}

View file

@ -85,10 +85,10 @@ impl fmt::Debug for AuthCredential {
pub enum AuthMech {
Anonymous,
Password,
PasswordBackupCode,
// Now represents TOTP.
#[serde(rename = "passwordmfa")]
PasswordTotp,
PasswordBackupCode,
PasswordSecurityKey,
Passkey,
}

View file

@ -19,7 +19,7 @@ pub use self::auth::*;
pub use self::unix::*;
/// The type of Account in use.
#[derive(Clone, Copy, Debug, ToSchema)]
#[derive(Serialize, Deserialize, Clone, Copy, Debug, ToSchema)]
pub enum AccountType {
Person,
ServiceAccount,

View file

@ -17,7 +17,13 @@ import yarl
from kanidm.models.group import Group, GroupList, IGroup, RawGroup
from kanidm.models.oauth2_rs import IOauth2Rs, OAuth2Rs, Oauth2RsList, RawOAuth2Rs
from kanidm.models.person import IPerson, Person, PersonList, RawPerson
from kanidm.models.person import (
IPerson,
Person,
PersonList,
RawPerson,
PersonCredentialResetToken,
)
from kanidm.models.service_account import (
IServiceAccount,
ServiceAccount,
@ -93,7 +99,7 @@ class KanidmClient:
"""Constructor for KanidmClient"""
self.logger = logger or getLogger(__name__)
self.instance_name = instance_name # TODO: use this in loaders etc
self.instance_name = instance_name # TODO: use this in loaders etc
if config is not None:
self.config = config
else:
@ -123,7 +129,7 @@ class KanidmClient:
def _configure_ssl(self) -> None:
"""Sets up SSL configuration for the client"""
if False in [self.config.verify_certificate, self.config.verify_hostnames ]:
if False in [self.config.verify_certificate, self.config.verify_hostnames]:
logging.debug("Setting up SSL context with no verification")
self._ssl_context = ssl.create_default_context(purpose=ssl.Purpose.SERVER_AUTH)
self._ssl_context.hostname_checks_common_name = False
@ -135,9 +141,8 @@ class KanidmClient:
raise FileNotFoundError(f"CA Path not found: {self.config.ca_path}")
else:
self.logger.debug("Setting up SSL context with CA path=%s", self.config.ca_path)
self._ssl_context = ssl.create_default_context(purpose=ssl.Purpose.SERVER_AUTH,cafile=self.config.ca_path)
self._ssl_context = ssl.create_default_context(purpose=ssl.Purpose.SERVER_AUTH, cafile=self.config.ca_path)
else:
logging.debug("Setting up default SSL context")
self._ssl_context = ssl.create_default_context(purpose=ssl.Purpose.SERVER_AUTH)
@ -521,9 +526,7 @@ class KanidmClient:
"""get an OAuth2 client"""
endpoint = f"{Endpoints.OAUTH2}/{rs_name}"
response: ClientResponse[IOauth2Rs] = await self.call_get(endpoint)
if response.status_code != 200:
raise ValueError(f"Failed to get oauth2 resource server: {response.content}")
if response.data is None:
if response.status_code != 200 or response.data is None:
raise ValueError(f"Failed to get oauth2 resource server: {response.content}")
return RawOAuth2Rs(**response.data).as_oauth2_rs
@ -583,9 +586,7 @@ class KanidmClient:
"""Get a service account"""
endpoint = f"{Endpoints.SERVICE_ACCOUNT}/{name}"
response: ClientResponse[IServiceAccount] = await self.call_get(endpoint)
if response.status_code != 200:
raise ValueError(f"Failed to get service account: {response.content}")
if response.data is None:
if response.status_code != 200 or response.data is None:
raise ValueError(f"Failed to get service account: {response.content}")
return RawServiceAccount(**response.data).as_service_account
@ -672,9 +673,7 @@ class KanidmClient:
"""Get a group"""
endpoint = f"{Endpoints.GROUP}/{name}"
response: ClientResponse[IGroup] = await self.call_get(endpoint)
if response.status_code != 200:
raise ValueError(f"Failed to get group: {response.content}")
if response.data is None:
if response.status_code != 200 or response.data is None:
raise ValueError(f"Failed to get group: {response.content}")
return RawGroup(**response.data).as_group
@ -719,9 +718,7 @@ class KanidmClient:
"""Get a person by name"""
endpoint = f"{Endpoints.PERSON}/{name}"
response: ClientResponse[IPerson] = await self.call_get(endpoint)
if response.status_code != 200:
raise ValueError(f"Failed to get person: {response.content}")
if response.data is None:
if response.status_code != 200 or response.data is None:
raise ValueError(f"Failed to get person: {response.content}")
return RawPerson(**response.data).as_person
@ -765,6 +762,19 @@ class KanidmClient:
endpoint = f"{Endpoints.PERSON}/{id}"
return await self.call_delete(endpoint)
async def person_account_credential_update_token(self, id: str, ttl: Optional[int] = None) -> PersonCredentialResetToken:
"""Create a password reset token for person with an optional time to live in seconds"""
endpoint = f"{Endpoints.PERSON}/{id}/_credential/_update_intent"
if ttl:
endpoint = f"{endpoint}/{ttl}"
response: ClientResponse[Any] = await self.call_get(endpoint)
if response.status_code != 200 or response.content is None:
raise ValueError(f"Failed to get token: {response.content}")
token = PersonCredentialResetToken.model_validate(json_lib.loads(response.content))
return token
async def person_account_post_ssh_key(self, id: str, tag: str, pubkey: str) -> ClientResponse[None]:
"""Create an SSH key for a user"""
endpoint = f"{Endpoints.PERSON}/{id}/_ssh_pubkeys"

View file

@ -38,8 +38,15 @@ class RawPerson(BaseModel):
uuid=UUID(self.attrs["uuid"][0]),
)
PersonList = RootModel[List[RawPerson]]
class IPerson(TypedDict):
attrs: Dict[str, List[str]]
class PersonCredentialResetToken(BaseModel):
token: str
expiry_time: int
model_config = ConfigDict(arbitrary_types_allowed=True)

View file

@ -1,4 +1,5 @@
""" kanidm RADIUS module """
"""kanidm RADIUS module"""
import asyncio
from aiohttp.client_exceptions import ClientConnectorError
from functools import reduce
@ -16,15 +17,26 @@ from .. import KanidmClient
from . import radiusd
from .utils import check_vlan
CONTAINER_CONFIG_FILE_PATH = "/data/radius.toml"
# the list of places to try
CONFIG_PATHS = [
os.getenv("KANIDM_RLM_CONFIG", "/data/kanidm"), # container goodness
"~/.config/kanidm", # for a user
"/etc/kanidm/kanidm", # system-wide
"../examples/kanidm", # test mode
os.getenv("KANIDM_RLM_CONFIG", CONTAINER_CONFIG_FILE_PATH), # container goodness
"~/.config/radius.toml", # for a user
"/etc/kanidm/radius.toml", # system-wide
"../examples/radius.toml", # test mode
"/data/kanidm", # fallback to old path
]
def find_radius_config_path() -> Optional[Path]:
for config_file_path in CONFIG_PATHS:
config_path = Path(config_file_path).expanduser().resolve()
if config_path.exists():
return config_path
return None
def instantiate(_: Any) -> Any:
"""start up radiusd"""
logging.basicConfig(
@ -33,16 +45,9 @@ def instantiate(_: Any) -> Any:
)
logging.info("Starting up!")
config_path = None
for config_file_path in CONFIG_PATHS:
config_path = Path(config_file_path).expanduser().resolve()
if config_path.exists():
break
if (config_path is None) or (not config_path.exists()):
logging.error(
"Failed to find configuration file, checked (%s), quitting!", CONFIG_PATHS
)
config_path = find_radius_config_path()
if config_path is None:
logging.error("Failed to find configuration file, checked (%s), quitting!", CONFIG_PATHS)
sys.exit(1)
kanidm_client = KanidmClient(config_file=config_path)
@ -107,9 +112,7 @@ def authorize(
tok = None
try:
loop = asyncio.get_event_loop()
tok = RadiusTokenResponse.model_validate(
loop.run_until_complete(_get_radius_token(username=user_id))
)
tok = RadiusTokenResponse.model_validate(loop.run_until_complete(_get_radius_token(username=user_id)))
logging.debug("radius information token: %s", tok)
except NoMatchingEntries as error_message:
logging.info(
@ -125,9 +128,7 @@ def authorize(
logging.error("kanidm exception: %s, %s", type(error_message), error_message)
return radiusd.RLM_MODULE_FAIL
if tok is None:
logging.info(
"kanidm RLM_MODULE_REJECT - unable to retrieve radius information token"
)
logging.info("kanidm RLM_MODULE_REJECT - unable to retrieve radius information token")
return radiusd.RLM_MODULE_REJECT
# Get values out of the token

View file

@ -9,7 +9,7 @@ import logging
from pathlib import Path
from typing import Any, Dict, List, Optional, Tuple
from authlib.jose import JsonWebSignature # type: ignore
from authlib.jose import JsonWebSignature # type: ignore
from pydantic import ConfigDict, BaseModel, Field
from . import TOKEN_PATH
@ -113,7 +113,7 @@ class ConfigInstance(BaseModel):
class TokenStore(BaseModel):
"""Represents the user auth tokens, so we can load them from the user store"""
instances: Dict[str, ConfigInstance] = Field({"" : {}})
instances: Dict[str, ConfigInstance] = Field({"": ConfigInstance.model_construct()})
def save(self, filepath: Path = TOKEN_PATH) -> None:
"""saves the cached tokens to disk"""

View file

@ -1,4 +1,5 @@
""" type objects """
# pylint: disable=too-few-public-methods
# ^ disabling this because pydantic models don't have public methods
@ -31,7 +32,7 @@ class ClientResponse(BaseModel, Generic[T]):
class AuthInitResponse(BaseModel):
"""Aelps parse the response from the Auth 'init' stage"""
"""Helps parse the response from the Auth 'init' stage"""
class _AuthInitState(BaseModel):
"""sub-class for the AuthInitResponse model"""
@ -146,9 +147,7 @@ class RadiusClient(BaseModel):
socket.gethostbyname(value)
return value
except socket.gaierror as error:
raise ValueError(
f"ipaddr value ({value}) wasn't an IP Address, Network or valid hostname: {error}"
)
raise ValueError(f"ipaddr value ({value}) wasn't an IP Address, Network or valid hostname: {error}")
class KanidmClientConfig(BaseModel):
@ -172,7 +171,6 @@ class KanidmClientConfig(BaseModel):
radius_cert_path: str = "/data/cert.pem"
radius_key_path: str = "/data/key.pem" # the signing key for radius TLS
radius_dh_path: str = "/data/dh.pem" # the diffie-hellman output
radius_ca_path: Optional[str] = None
radius_ca_dir: Optional[str] = None
@ -196,9 +194,7 @@ class KanidmClientConfig(BaseModel):
uri = urlparse(value)
valid_schemes = ["http", "https"]
if uri.scheme not in valid_schemes:
raise ValueError(
f"Invalid URL Scheme for uri='{value}': '{uri.scheme}' - expected one of {valid_schemes}"
)
raise ValueError(f"Invalid URL Scheme for uri='{value}': '{uri.scheme}' - expected one of {valid_schemes}")
# make sure the URI ends with a /
if not value.endswith("/"):

View file

@ -1,4 +1,4 @@
""" utility functions """
"""utility functions"""
from pathlib import Path
from typing import Any, Dict, Union

Some files were not shown because too many files have changed in this diff Show more