The stand-in page in the admin panel asked an administrator of an
organization for their vault master password inside the panel of the server
operator, which are two different roles, and it carried its own partial
login: no Argon2, no two-step login, and no fingerprint of the asking device
to compare against.
The page belongs where that already exists. The web vault has the whole
login stack and, in its AGPL part, the same unwrap the approval needs, since
account recovery does it too. Upstream keeps only the page itself in the
licensed part; the navigation entry and the string for it are already in
every build.
So the endpoints stay and the page goes, to be added to the web vault build
instead. The notification mail points at the route it lives under there. A
member who loses every trusted device is not stranded meanwhile: account
recovery gets them back in under the same conditions, at the price of a new
master password.
Findings from a review of the earlier commits.
A key rotation dropped the device key pairs along with the wrapped user
keys, so the devices listed in `/devices/update-trust` could never be
trusted again and silently lost their trust on every rotation. Those key
pairs are wrapped with the device key, which a rotation does not touch, so
they now stay and the re-wrap works. The invalidation also moved ahead of
the new user key: failing after it had been written left devices handing
out a key that no longer opens the vault.
The three key blobs are now checked against the shape of an `EncString`
instead of only for emptiness, as upstream does, which also keeps
multi-megabyte values out of those columns.
`/auth-requests/admin-request` is rate limited and reuses the open request
of a device instead of adding one per attempt, which mailed every
administrator again each time. Only confirmed memberships are asked, and
answered: an invitation that was never accepted is not a membership yet, a
revoked one is not one anymore, and neither should learn the address, the
IP and the device of the asker. `UserDecryptionOptions` reports the same
condition, so no way out is announced that would be refused when taken.
The bulk endpoints skip what they cannot answer rather than failing the
whole call after having answered everything before it, matching upstream,
and are bounded. The purge does its work per type in the database instead
of reading the table and deleting row by row, with indexes to go with it.
Also: approving an auth request is limited to the newest one of a device,
`GET /auth-requests/<id>` refuses an expired request like the anonymous
lookup already did, the approval notification addresses the device that
asked rather than the administrator's, and accepting an invitation while
enrolling is tied to the trusted device flow it was meant for.
Lets a user unlock their vault after an SSO login with a key stored on a
trusted device instead of a master password, what Bitwarden calls trusted
device encryption. Off by default, enabled with
`SSO_TRUSTED_DEVICE_ENCRYPTION`, which requires `SSO_ENABLED`.
The client generates a key pair plus a device key that never leaves the
device and stores three blobs on the device row: the user key wrapped for
the device public key, that public key wrapped with the user key, and the
device private key wrapped with the device key. The server only keeps and
returns them, so a stored trust is worthless without the device itself.
A device counts as trusted only while all three are present.
Endpoints, matching bitwarden/server's DevicesController:
PUT|POST /devices/<identifier>/keys trust a device
POST /devices/<identifier>/retrieve-keys the public halves, for rotation
POST /devices/update-trust re-wrap after a key rotation
POST /devices/untrust drop the trust of some devices
POST /devices/lost-trust client reports a drifted trust
`GET /devices`, `GET /devices/identifier/<id>` and the login response now
report the real trust state instead of a hard-coded `isTrusted: false`.
An SSO login response carries `UserDecryptionOptions.TrustedDeviceOption`,
which is what makes the clients offer the flow at all. Upstream ties this to
the SSO configuration of an organization; SSO is configured for the whole
server here, so the setting decides it, and members of no organization can
use it too. A password login never gets these options. When the setting is
turned off again, devices that are still trusted keep receiving their keys
with `IsTdeOffboarding` set, so their owner can still unlock and set a
master password instead of being locked out.
`HasAdminApproval` and `HasManageResetPasswordPermission` are always false:
approval of a new device by an organization admin is not implemented, and
announcing it would leave the client waiting for a request nobody can
answer. A new device is unlocked by approving it from an already trusted
device or with the master password.
Two adjacent fixes this depends on:
- `POST /accounts/keys` refused to notice that an account already has a
key pair and would happily replace it, which makes every existing
cipher undecryptable. It now only accepts keys for an account that has
none, and tolerates a repeat of the same keys. The trusted device flow
is what makes this reachable in practice: a client that misjudges an
existing account as new posts a fresh key pair here.
- `POST /accounts/set-password` keyed "account already initialized" off
the key pair, so an account created without a master password could
never gain one. It now keys off the master password itself and refuses
to replace an existing key pair, which is what the check was guarding.
Rotating the account keys leaves every device holding a wrapped copy of the
previous user key. Those are dropped; the rotating device keeps its own
private key so its client can re-wrap the new user key right away via
`/devices/update-trust`. A client that skips that call ends up with no
trusted device rather than a broken unlock.
Covers dani-garcia/vaultwarden#7034.
* Panic on unrecognised DATABASE_URL instead of silent SQLite fallback
Previously, any DATABASE_URL that did not match the mysql: or postgresql:
prefix was silently treated as a SQLite file path. This caused data loss
in containerised environments when the URL was misconfigured (typos,
quoting issues), as vaultwarden would create an ephemeral SQLite database
that was wiped on restart.
Now, an explicit sqlite:// prefix is supported and used as the default.
Bare paths without a recognised scheme are still accepted for backwards
compatibility, but only if the database file already exists. If not, the
process panics with a clear error message.
Relates to #2835, #1910, #860.
* Use err!() instead of panic!() for unrecognised DATABASE_URL
Follow the established codebase convention where configuration
validation errors use err!() to propagate gracefully, rather than
panic!(). The error propagates through from_config() and is caught
by create_db_pool() which logs and calls exit(1).
* Use 'scheme' instead of 'prefix' in DATABASE_URL messages
Per review feedback, 'scheme' is the more accurate term for the
sqlite:// portion of the URL.
* Update Feature Flags
Added new feature flags which could be supported without issues.
Removed all deprecated feature flags and only match supported flags.
Do not error on invalid flags during load, but do on config save via admin interface.
During load it will print a `WARNING`, this is to prevent breaking setups when flags are removed, but are still configured.
There are no feature flags anymore currently needed to be set by default, so those are removed now.
Signed-off-by: BlackDex <black.dex@gmail.com>
* Adjust code a bit and add Diagnostics check
Signed-off-by: BlackDex <black.dex@gmail.com>
* Update .env template
Signed-off-by: BlackDex <black.dex@gmail.com>
---------
Signed-off-by: BlackDex <black.dex@gmail.com>
This PR adds an option to prefer IPv6 resolving before IPv4.
On IPv6 only systems this could be very useful, but will not solve IPv4 only domains of course.
For that you need a DNS64 + NAT64 solution
Fixes#6301
Signed-off-by: BlackDex <black.dex@gmail.com>
* Add SSO functionality using OpenID Connect
Co-authored-by: Pablo Ovelleiro Corral <mail@pablo.tools>
Co-authored-by: Stuart Heap <sheap13@gmail.com>
Co-authored-by: Alex Moore <skiepp@my-dockerfarm.cloud>
Co-authored-by: Brian Munro <brian.alexander.munro@gmail.com>
Co-authored-by: Jacques B. <timshel@github.com>
* Improvements and error handling
* Stop rolling device token
* Add playwright tests
* Activate PKCE by default
* Ensure result order when searching for sso_user
* add SSO_ALLOW_UNKNOWN_EMAIL_VERIFICATION
* Toggle SSO button in scss
* Base64 encode state before sending it to providers
* Prevent disabled User from SSO login
* Review fixes
* Remove unused UserOrganization.invited_by_email
* Split SsoUser::find_by_identifier_or_email
* api::Accounts::verify_password add the policy even if it's ignored
* Disable signups if SSO_ONLY is activated
* Add verifiedDate to organizations::get_org_domain_sso_details
* Review fixes
* Remove OrganizationId guard from get_master_password_policy
* Add wrapper type OIDCCode OIDCState OIDCIdentifier
* Membership::confirm_user_invitations fix and tests
* Allow set-password only if account is unitialized
* Review fixes
* Prevent accepting another user invitation
* Log password change event on SSO account creation
* Unify master password policy resolution
* Upgrade openidconnect to 4.0.0
* Revert "Remove unused UserOrganization.invited_by_email"
This reverts commit 548e19995e141314af98a10d170ea7371f02fab4.
* Process org enrollment in accounts::post_set_password
* Improve tests
* Pass the claim invited_by_email in case it was not in db
* Add Slack configuration hints
* Fix playwright tests
* Skip broken tests
* Add sso identifier in admin user panel
* Remove duplicate expiration check, add a log
* Augment mobile refresh_token validity
* Rauthy configuration hints
* Fix playwright tests
* Playwright upgrade and conf improvement
* Playwright tests improvements
* 2FA email and device creation change
* Fix and improve Playwright tests
* Minor improvements
* Fix enforceOnLogin org policies
* Run playwright sso tests against correct db
* PKCE should now work with Zitadel
* Playwright upgrade maildev to use MailBuffer.expect
* Upgrades playwright tests deps
* Check email_verified in id_token and user_info
* Add sso verified endpoint for v2025.6.0
* Fix playwright tests
* Create a separate sso_client
* Upgrade openidconnect to 4.0.1
* Server settings for login fields toggle
* Use only css for login fields
* Fix playwright test
* Review fix
* More review fix
* Perform same checks when setting kdf
---------
Co-authored-by: Felix Eckhofer <felix@eckhofer.com>
Co-authored-by: Pablo Ovelleiro Corral <mail@pablo.tools>
Co-authored-by: Stuart Heap <sheap13@gmail.com>
Co-authored-by: Alex Moore <skiepp@my-dockerfarm.cloud>
Co-authored-by: Brian Munro <brian.alexander.munro@gmail.com>
Co-authored-by: Jacques B. <timshel@github.com>
Co-authored-by: Timshel <timshel@480s>
* Abstract file access through Apache OpenDAL
* Add AWS S3 support via OpenDAL for data files
* PR improvements
* Additional PR improvements
* Config setting comments for local/remote data locations
* WIP Sync with Upstream
WIP on syncing API Responses with upstream.
This to prevent issues with new clients, and find possible current issues like members, collections, groups etc..
Signed-off-by: BlackDex <black.dex@gmail.com>
* More API Response fixes
- Some 2fa checks
- Some org checks
- Reconfigured the experimental flags and noted which are deprecated
Also removed some hard-coded defaults.
- Updated crates
Signed-off-by: BlackDex <black.dex@gmail.com>
* Add avatar color to emergency access api
Signed-off-by: BlackDex <black.dex@gmail.com>
* Fix spelling and some crate updates
Signed-off-by: BlackDex <black.dex@gmail.com>
* Use PushId and always generate the PushId
Signed-off-by: BlackDex <black.dex@gmail.com>
* Fix clippy lints
Signed-off-by: BlackDex <black.dex@gmail.com>
* Fix several Push issues and API's
Signed-off-by: BlackDex <black.dex@gmail.com>
* Check if push_uuid is empty and generate when needed
Signed-off-by: BlackDex <black.dex@gmail.com>
* Updated some comments and removed old export format
Signed-off-by: BlackDex <black.dex@gmail.com>
* cargo update
Signed-off-by: BlackDex <black.dex@gmail.com>
* Fix bulk edit Fixes#5737
Signed-off-by: BlackDex <black.dex@gmail.com>
* Send an email when an account exists already
When you want to change your email address into an account which already exists, upstream sends an email to the existing account.
Lets do the same.
Kinda fixes#5630
Signed-off-by: BlackDex <black.dex@gmail.com>
* Update 2fa removal/revoke email
Signed-off-by: BlackDex <black.dex@gmail.com>
* Allow col managers to import
This commit adds functionality to allow users with manage access to a collection, or managers with all access to import into an organization.
Fixes#5592
Signed-off-by: BlackDex <black.dex@gmail.com>
* Filter deprected flags and only return active flags
Signed-off-by: BlackDex <black.dex@gmail.com>
* Fix grammer
Signed-off-by: BlackDex <black.dex@gmail.com>
* Rename Small to Compact
Signed-off-by: BlackDex <black.dex@gmail.com>
* Rebase with upstream and fix conflicts
Signed-off-by: BlackDex <black.dex@gmail.com>
---------
Signed-off-by: BlackDex <black.dex@gmail.com>
Bitwarden allows to use self-hosted forwarded email services.
But for this to work you need to add custom URL's to the `connect-src` CSP entry.
This commit allows setting this and checks if the URL starts with `https://` else it will abort loading.
Fixes#5290
Signed-off-by: BlackDex <black.dex@gmail.com>
* fix password hint check
don't show password hints if you have disabled the hints with
PASSWORD_HINTS_ALLOWED=false or if you have not configured mail and
opted into showing password hints
* update descriptions for pw hints options
* Allow enforcing Single Org with pw reset policy
Bitwarden only allows the Reset Password policy to be set when the Single Org policy is enabled already.
This PR adds a check so that this can be enforced when a config option is enabled.
Since Vaultwarden encouraged to use multiple orgs when groups were not available yet we should not enable this by default now.
This might be something to do in the future.
When enabled, it will prevent the Reset Password policy to be enabled if the Single Org policy is not enabled.
It will also prevent the Single Org policy to be disabled if the Reset Password policy is enabled.
Fixes#4855
Signed-off-by: BlackDex <black.dex@gmail.com>
* Removed some extra if checks
Signed-off-by: BlackDex <black.dex@gmail.com>
---------
Signed-off-by: BlackDex <black.dex@gmail.com>
This PR adds a config option to allow the note size to increase to 100_000, instead of the default 10_000.
Since this might cause issues with the clients (in the future), and will cause issues with importing into a Bitwarden server, i added warnings regarding this.
Closes#3168
* Add initial working Duo Universal Prompt support.
* Add db schema and models for Duo 2FA state storage
* store duo states in the database and validate during authentication
* cleanup & comments
* bump state/nonce length
* replace stray use of TimeDelta
* more cleanup
* bind Duo oauth flow to device id, drop redundant device type handling
* drop redundant alphanum string generation code
* error handling cleanup
* directly use JWT_VALIDITY_SECS constant instead of copying it to DuoClient instances
* remove redundant explicit returns, rustfmt
* rearrange constants, update comments, error message
* override charset on duo state column to ascii for mysql
* Reduce twofactor_duo_ctx state/nonce column size in postgres and maria
* Add fixes suggested by clippy
* rustfmt
* Update to use the make_http_request
* Don't handle OrganizationDuo
* move Duo API endpoint fmt strings out of macros and into format! calls
* Add missing indentation
Co-authored-by: Daniel García <dani-garcia@users.noreply.github.com>
* remove redundant expiry check when purging Duo contexts
---------
Co-authored-by: BlackDex <black.dex@gmail.com>
Co-authored-by: Daniel García <dani-garcia@users.noreply.github.com>
* Remove custom WebSocket code
Remove our custom WebSocket code and only use the Rocket code.
Removed all options in regards to WebSockets
Added a new option `WEBSOCKET_DISABLED` which defaults too `false`.
This can be used to disable WebSockets if you really do not want to use it.
* Addressed remarks given and some updates
- Addressed comments given during review
- Updated crates, including Rocket to the latest merged v0.5 changes
- Removed an extra header which should not be sent for websocket connections
* Updated suggestions and crates
- Addressed the suggestions
- Updated Rocket to latest rc4
Also made the needed code changes
- Updated all other crates
Pinned `openssl` and `openssl-sys`
---------
Co-authored-by: Daniel García <dani-garcia@users.noreply.github.com>
* fix: update env template for systemd compatibility
Adjust env template to ensure compatibility with systemd's EnvironmentFile parsing, which only recognizes line-starting comment symbols.
* Refactor SMTP and Rocket settings in .env.template
- Simplify the SMTP_SECURITY and SMTP_PORT options by providing a list of choices and default values
- Clarify the ROCKET_PORT default value depending on the environment (Docker or not)
* update env template to fit the config.rs
* Categorize env template settings
* Fix a wrong setting
* Fix wrong icon redirect code
* Fix ICON_DOWNLOAD_TIMEOUT default value
Co-authored-by: Daniel <daniel.barabasa@gmail.com>
* Move related settings together.
Merge Yubikey, Duo, Email 2FA sections into one.
Other minor fixes.
* Minor fix of some settings position
* Add some comment
* Minor fix.
---------
Co-authored-by: Daniel <daniel.barabasa@gmail.com>
* Allow customizing the featureStates
Use a comma separated list of features to enable using the FEATURE_FLAGS env variable
* Move feature flag parsing to util
* Fix formatting
* Update supported feature flags
* Rename feature_flags to experimental_client_feature_flags
Additionally, use a caret (^) instead of an exclamation mark (!) to disable features
* Fix formatting issue.
* Add documentation to env template
* Remove functionality to disable feature flags
* Fix JSON key for feature states
* Convert error to warning when feature flag is unrecognized
* Simplify parsing of feature flags
* Fix default value of feature flags in env template
* Fix formatting