Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions src/vaultwarden/models/bitwarden.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from typing import Generic, Literal, TypeVar, cast
from uuid import UUID

from httpx import Response
from pydantic import AliasChoices, Field, TypeAdapter, field_validator
from pydantic_core.core_schema import FieldValidationInfo

Expand Down Expand Up @@ -483,6 +484,22 @@ def user_search(
return None
return users[0]

def change_user_type(
self, user: OrganizationUserDetails, premissions: OrganizationUserType
) -> Response:
payload = {
"collections": [],
"groups": [],
"permissions": {"response": None},
"type": premissions,
"accessSecretsManager": False,
}

resp = self.api_client.api_request(
"PUT", f"api/organizations/{self.Id}/users/{user.Id}", json=payload
)
return resp

def _get_collections(self) -> list[OrganizationCollection]:
resp = self.api_client.api_request(
"GET", f"api/organizations/{self.Id}/collections"
Expand Down
10 changes: 9 additions & 1 deletion tests/e2e/test_bitwarden.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

from vaultwarden.clients.bitwarden import BitwardenAPIClient
from vaultwarden.models.bitwarden import get_organization
from vaultwarden.models.enum import OrganizationUserType

# Get Bitwarden credentials from environment variables
url = os.environ.get("BITWARDEN_URL", None)
Expand Down Expand Up @@ -40,7 +41,7 @@ def setUp(self) -> None:
).users()

def test_get_organization_users(self):
self.assertEqual(len(self.test_users), 2)
self.assertEqual(len(self.test_users), 3)

def test_get_organization_items(self):
self.assertEqual(len(self.test_org_ciphers), 1)
Expand All @@ -62,6 +63,13 @@ def test_get_users_of_collection_1(self):
def test_get_users_of_collection_2(self):
self.assertEqual(len(self.test_collection_2_users), 1)

def test_change_user_type_organization(self):
user = self.organization.user_search("test-account-3@example.com")
resp = self.organization.change_user_type(user, OrganizationUserType.Admin)
self.assertTrue(resp.is_success)
resp = self.organization.change_user_type(user, OrganizationUserType.User)
self.assertTrue(resp.is_success)

def test_create_delete_collection(self):
len_old_colls = len(self.organization.collections(force_refresh=True))
new_coll = self.organization.create_collection("create_delete_test")
Expand Down
4 changes: 2 additions & 2 deletions tests/fixtures/server/db.sqlite3
Git LFS file not shown
101 changes: 101 additions & 0 deletions tests/fixtures/test-accout-3/profile_camel.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
{
"ciphers": [],
"collections": [],
"domains": null,
"folders": [],
"object": "sync",
"policies": [],
"profile": {
"_status": 0,
"avatarColor": null,
"creationDate": "2025-09-17T12:16:51.538080Z",
"culture": "en-US",
"email": "test-account-3@example.com",
"emailVerified": true,
"forcePasswordReset": false,
"id": "73f2a96c-7718-4e7c-9aa1-0f4e319ad01f",
"key": "2.7NJ7sUyRw82IIAEtFK++ow==|LN+cuL+YiO4XoiGAsOXoE3dXyHPTzq6G+/etMtbnCOyo7FvONmMH7+61n3VTruxMCpaZLQ7d3GxIWy2YsNp1WpxMMu0XxOUxtH82ZOQkLRI=|3Dq09MHhvbHWunlxeLpodpVWRiSIYPR4/U1Mp2hnG1U=",
"name": "test-account-3",
"object": "profile",
"organizations": [
{
"accessSecretsManager": false,
"allowAdminAccessToAllCollectionItems": true,
"enabled": true,
"familySponsorshipAvailable": false,
"familySponsorshipFriendlyName": null,
"familySponsorshipLastSyncDate": null,
"familySponsorshipToDelete": null,
"familySponsorshipValidUntil": null,
"hasPublicAndPrivateKeys": true,
"id": "cda840d2-1de0-4f31-bd49-b30dacd7e8b0",
"identifier": null,
"key": "4.DDwoeFcsONwgnd9AJubUqEnzRoqRdHz5GluDPX4te+8FrlnVB35RNMkB9xQ76n0eIP3HbzXFixNZDh7rENd6D4RHeu4V8SA3dhZb9Y6wcfArCg2As8QBHmnbFPvdJWyLTWSbNDs9/SwawMdFpRUuDaPTHV7kWjmW4H5xIfKbN6YIpNo3C1pi2bXSqUZRuGbA01bnvn1xtL2cToEc8pDx52C8MSKCCRW3dysM6ob3I6zOwR911C6Ympd1rzXBFfBdrSTQlTA3RHo0tnTko/TmYil6vgcdo8NrfIwQOcSX/fzbcpgYaMwGYwZ5YxCMW+N9neu2YvXYmhvDwMXNsijv3Q==",
"keyConnectorEnabled": false,
"keyConnectorUrl": null,
"limitCollectionCreation": true,
"limitCollectionDeletion": true,
"limitItemDeletion": false,
"maxCollections": null,
"maxStorageGb": 32767,
"name": "Test Organization",
"object": "profileOrganization",
"organizationUserId": "2a9297d1-2619-47df-aa26-ee7721257570",
"permissions": {
"accessEventLogs": false,
"accessImportExport": false,
"accessReports": false,
"createNewCollections": false,
"deleteAnyCollection": false,
"editAnyCollection": false,
"manageGroups": false,
"managePolicies": false,
"manageResetPassword": false,
"manageScim": false,
"manageSso": false,
"manageUsers": false
},
"productTierType": 3,
"providerId": null,
"providerName": null,
"providerType": null,
"resetPasswordEnrolled": false,
"seats": null,
"selfHost": true,
"ssoBound": false,
"status": 2,
"type": 2,
"use2fa": true,
"useActivateAutofillPolicy": false,
"useAdminSponsoredFamilies": false,
"useApi": true,
"useCustomPermissions": true,
"useDirectory": false,
"useEvents": false,
"useGroups": false,
"useKeyConnector": false,
"usePasswordManager": true,
"usePolicies": true,
"useResetPassword": false,
"useRiskInsights": false,
"useScim": false,
"useSecretsManager": false,
"useSso": false,
"useTotp": true,
"userId": "73f2a96c-7718-4e7c-9aa1-0f4e319ad01f",
"userIsClaimedByOrganization": false,
"userIsManagedByOrganization": false,
"usersGetPremium": true
}
],
"premium": true,
"premiumFromOrganization": false,
"privateKey": "2.Ps14TCZ66rbYU+xXCrfkHQ==|Ms1SQM0GAs258Ls1RNoHoE6zTLy/MRXqJzPT/E8cfig2Tn0vfrYoVwppTJNOExDTzoS02yG73KFsOM83YvsiB7E5MeM445Q18EUGKdIW6WyIeYBCVxm+TmeyEWBW6r9tGhxV8iv+RRpdxPQVQYFZbqP92/ugzleSnh2rrUU02hIr9dxMQADtEyLu2VqTu2YH63Ljh6AWOtzUcvFgG/5izNjfZFgoIb0rdAn9oGQwxXF06LA/htClgCw59S0kEwVJqOC54VDYYDfLb66HbG4eogVvIsRbMrbgxuuwoTThW88frJyMIun2Z1eLNkx73LThA83g1N6fK1ko0zNR94E2y2+VgeWmZvZnKr579dXxc47Xe+5eauZ4AYBHDrhLs9sLXVNGr4wCtszUaJ00GFHPBlATsl2TjQyyq47dDRKm7UtiOBox/zOEKuyYAn4XkmPxDo6+/ltCIMqUuR3rdpbk9CmjUW41bO09+LysTleeYoMumVJYpz/03IP11oHKLbmqjCDnT6WfcfdEmlbFROgTuJxEn4lLncN9102qJxXsYWRyVLrymEFS3cwOml0urrutiQkizR5V9U1LtJ4uuJTRFE9/hbv4m/pcdTNbN+vP/66C6rOB3ZTEyhQ3CPD9b7bRONsJtVAP03LrRqp57uejkqh4G02zWLfSBqHzKVryvBRzETIQEiXesvXdftY+zeEm2XtHQRFOmw5syJK75wS76uxRcrLh3vOQzI19tkqKrvaLgW9CgCsET3P13ZEzM+6JZ33P3W4I3NortjBX/fBDFjsQn6fXLipLKraf2sizURCVcKsaw09qlSgxD+E7ynedXGGnG82L7IpWahKtL3TxbPSm+xS3XUICpFHS8hEmL5kFdzF+JmNe8Oh5MwIL3+H4K6sKx2ebjc5UfZmAZs9q+RaJdvOQupvGHaB28OOGUmdr2g3d4s8vTGOiIMfkoUmDYlUwTXrO3izWtA0ojJ3NJ32up63m0rpSByUkSlvcTor3V+MpVjg4PQjZCFTfSgalwyzu+sI/MjZ3R9EvTXPV3lOmvu3PtE6sEPby0s2qNg11KUGz2qPT1D2Y0YjTYF/TLjcTmeYrTgdDXzu/s34prHCJsAWfVtENc12R8KUVfmzmpf31YCoXrdgZHlcQ1LcC2S/2cT6kc059tcth4v7uTbg+IdMMB1RBUCcH1/ELCUSDhszy4daWRwcAaCyVImRFclP6nISYheQH7iTOHXQEb0KN20WozqJT1LXhKAoBPhOoMOemTExGvn291nTt9SnVtY+a1FJLtxymySBr/QggWnYItzXY2nRFTPpYcOTU3YOoYnMvLTnSEJA++lsleHHcuL2yu1XvZcX4jt6kSjXn375/G8Wj1d1VY194sl006TU5u1KjUuziq1vvg6M5/XIUQszvFdKz11qahWiUK2IIIEvC+NF3cC9YkodxgwVs4D4d0bpoVKDX2dadJFJpzW/Vfu9mM2w4P7TBKPl4fhzaS8BRledfohh+w9cOzZRHbHLxx3P4X8fkomVhFZxifP59JDwce/GO6VawyXPoKtATMc2rkdohrSC2H1Ic3mH5DZuvozEIwk710h+Jyo0K61QQ2Jf+EMbnj1tuAbS184TcgHIk70oGJOmcvnHsgVROt/I=|fa6RVD5+omu4W2K/f5GlyCq8vhWe3zfUbcRBpvCLPaQ=",
"providerOrganizations": [],
"providers": [],
"securityStamp": "b0cf4238-a77a-424c-8ff2-176f314e1378",
"twoFactorEnabled": false,
"usesKeyConnector": false
},
"sends": []
}