Tree:
054a249004
cached-config-operations
main
revert-7033-patch-1
test_dylint
v2-registration
0.10.0
0.11.0
0.12.0
0.13.0
0.9.0
1.0.0
1.1.0
1.10.0
1.11.0
1.12.0
1.13.0
1.13.1
1.14
1.14.1
1.14.2
1.15.0
1.15.1
1.16.0
1.16.1
1.16.2
1.16.3
1.17.0
1.18.0
1.19.0
1.2.0
1.20.0
1.21.0
1.22.0
1.22.1
1.22.2
1.23.0
1.23.1
1.24.0
1.25.0
1.25.1
1.25.2
1.26.0
1.27.0
1.28.0
1.28.1
1.29.0
1.29.1
1.29.2
1.3.0
1.30.0
1.30.1
1.30.2
1.30.3
1.30.4
1.30.5
1.31.0
1.32.0
1.32.1
1.32.2
1.32.3
1.32.4
1.32.5
1.32.6
1.32.7
1.33.0
1.33.1
1.33.2
1.34.0
1.34.1
1.34.2
1.34.3
1.35.0
1.35.1
1.35.2
1.35.3
1.35.4
1.35.5
1.35.6
1.35.7
1.35.8
1.36.0
1.37.0
1.37.1
1.4.0
1.5.0
1.6.0
1.6.1
1.7.0
1.8.0
1.9.0
1.9.1
${ noResults }
2 Commits (054a24900406afd5736614fc02866db12bd55f98)
| Author | SHA1 | Message | Date |
|---|---|---|---|
|
|
054a249004 |
Harden the trusted device flow
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. |
2 weeks ago |
|
|
dbeec752b8 |
Add device approval by an organization administrator
Completes the trusted device flow for the case it was missing: a member who
unlocks with a trusted device, has no other device of their own left to ask,
and therefore has no way back into their vault. They can now turn to the
administrators of their organization, who hand them their own user key
encrypted for the key pair of the asking device.
New `atype` on auth_requests, mirroring bitwarden/server's AuthRequestType.
It decides who may answer a request and how long it stays open: 15 minutes
between the user's own devices, a week for an administrator, and half a day
for their answer once given. The purge job applies that per type instead of
dropping everything after 15 minutes, and both the answer and the anonymous
lookup now refuse an expired request, which they did not before.
POST /auth-requests/admin-request ask, one request per org
GET /organizations/<id>/auth-requests what is waiting for an answer
POST /organizations/<id>/auth-requests/<id> approve or deny one
POST /organizations/<id>/auth-requests/deny deny several
POST /organizations/<id>/auth-requests answer several
Asking requires authentication, so the anonymous `POST /auth-requests` now
refuses the type. Answering goes through the organization the request was
addressed to and needs admin rights there; the asking user cannot answer
their own request through `PUT /auth-requests/<id>`, which would make the
whole detour pointless. A denial is saved but not announced, so a request
that did not come from the member does not learn that it was seen. The
administrator's view leaves out the access code, which is the asking
device's proof and none of their business.
The administrators are mailed when a request arrives, the member when one of
their devices was let in, so an approval nobody asked for does not pass
unnoticed.
Two fixes without which none of this is reachable from a client:
- `UserDecryptionOptions.TrustedDeviceOption` reported `HasAdminApproval`
and `HasManageResetPasswordPermission` as a flat false. The clients
decide on `hasAdminApproval || hasMasterPassword` whether a login is a
returning user or a brand new one, so a member without a master password
was shown the screen for creating an account, on every device but the
one they first trusted. Both are now derived from the account recovery
enrollment and the role.
- `PUT /organizations/<id>/users/<id>/reset-password-enrollment` demanded a
master password whenever a key was supplied. An account that unlocks
with a trusted device has none, and the clients send nothing but the key
when they enroll during registration, so enrolling was impossible for
exactly the accounts that need it most. Upstream carves out the same
exception, keyed on the organization's SSO configuration rather than on
a server-wide setting as here. Enrolling now also accepts a pending
invitation, as upstream does, so a just-provisioned member does not stay
invited forever with nobody able to confirm them.
|
2 weeks ago |