1
0
mirror of https://github.com/bitwarden/server.git synced 2025-07-02 16:42:50 -05:00

Merge branch 'master' into flexible-collections/deprecate-custom-collection-perm

# Conflicts:
#	src/Api/AdminConsole/Controllers/OrganizationUsersController.cs
#	src/Api/Vault/AuthorizationHandlers/Collections/CollectionAuthorizationHandler.cs
#	test/Api.Test/Vault/AuthorizationHandlers/CollectionAuthorizationHandlerTests.cs
This commit is contained in:
Rui Tome
2023-11-23 16:36:52 +00:00
191 changed files with 3610 additions and 4080 deletions

292
.vscode/launch.json vendored
View File

@ -7,94 +7,251 @@
{ {
"name": "Min Server", "name": "Min Server",
"configurations": [ "configurations": [
"Identity", "run-Identity",
"API" "run-API"
], ],
"presentation": { "presentation": {
"hidden": false, "hidden": false,
"group": "AA_compounds", "group": "AA_compounds",
"order": 1 "order": 1
}, },
"preLaunchTask": "buildIdentityApi",
"stopAll": true "stopAll": true
}, },
{ {
"name": "Admin, API, Identity", "name": "Admin, API, Identity",
"configurations": [ "configurations": [
"Admin", "run-Admin",
"API", "run-API",
"Identity" "run-Identity"
], ],
"presentation": { "presentation": {
"hidden": false, "hidden": false,
"group": "AA_compounds", "group": "AA_compounds",
"order": 3 "order": 3
}, },
"preLaunchTask": "buildIdentityApiAdmin",
"stopAll": true "stopAll": true
}, },
{ {
"name": "Full Server", "name": "Full Server",
"configurations": [ "configurations": [
"Admin", "run-Admin",
"API", "run-API",
"EventsProcessor", "run-EventsProcessor",
"Identity", "run-Identity",
"Sso", "run-Sso",
"Icons", "run-Icons",
"Billing", "run-Billing",
"Notifications" "run-Notifications"
], ],
"presentation": { "presentation": {
"hidden": false, "hidden": false,
"group": "AA_compounds", "group": "AA_compounds",
"order": 4 "order": 4
}, },
"preLaunchTask": "buildFullServer",
"stopAll": true "stopAll": true
}, },
{ {
"name": "Self Host: Bit", "name": "Self Host: Bit",
"configurations": [ "configurations": [
"Admin-SelfHost", "run-Admin-SelfHost",
"API-SelfHost", "run-API-SelfHost",
"EventsProcessor-SelfHost", "run-EventsProcessor-SelfHost",
"Identity-SelfHost", "run-Identity-SelfHost",
"Sso-SelfHost", "run-Sso-SelfHost",
"Notifications-SelfHost" "run-Notifications-SelfHost"
], ],
"presentation": { "presentation": {
"hidden": false, "hidden": false,
"group": "AA_compounds", "group": "AA_compounds",
"order": 2 "order": 2
}, },
"preLaunchTask": "buildSelfHostBit",
"stopAll": true "stopAll": true
}, },
{ {
"name": "Self Host: OSS", "name": "Self Host: OSS",
"configurations": [ "configurations": [
"Admin-SelfHost", "run-Admin-SelfHost",
"API-SelfHost", "run-API-SelfHost",
"EventsProcessor-SelfHost", "run-EventsProcessor-SelfHost",
"Identity-SelfHost", "run-Identity-SelfHost",
], ],
"presentation": { "presentation": {
"hidden": false, "hidden": false,
"group": "AA_compounds", "group": "AA_compounds",
"order": 99 "order": 99
}, },
"preLaunchTask": "buildSelfHostOss",
"stopAll": true "stopAll": true
} },
],
"configurations": [
{ {
"name": "Identity", "name": "Admin",
"configurations": [
"run-Admin"
],
"presentation": { "presentation": {
"hidden": false, "hidden": false,
"group": "cloud", "group": "cloud",
"order": 10 },
"preLaunchTask": "buildAdmin",
},
{
"name": "API",
"configurations": [
"run-API"
],
"presentation": {
"hidden": false,
"group": "cloud",
},
"preLaunchTask": "buildAPI",
},
{
"name": "Billing",
"configurations": [
"run-Billing"
],
"presentation": {
"hidden": false,
"group": "cloud",
},
"preLaunchTask": "buildBilling",
},
{
"name": "Events Processor",
"configurations": [
"run-EventsProcessor"
],
"presentation": {
"hidden": false,
"group": "cloud",
},
"preLaunchTask": "buildEventsProcessor",
},
{
"name": "Icons",
"configurations": [
"run-Icons"
],
"presentation": {
"hidden": false,
"group": "cloud",
},
"preLaunchTask": "buildIcons",
},
{
"name": "Identity",
"configurations": [
"run-Identity"
],
"presentation": {
"hidden": false,
"group": "cloud",
},
"preLaunchTask": "buildIdentity",
},
{
"name": "Notifications",
"configurations": [
"run-Notifications"
],
"presentation": {
"hidden": false,
"group": "cloud",
},
"preLaunchTask": "buildNotifications",
},
{
"name": "SSO",
"configurations": [
"run-Sso"
],
"presentation": {
"hidden": false,
"group": "cloud",
},
"preLaunchTask": "buildSso",
},
{
"name": "Admin Self Host",
"configurations": [
"run-Admin-SelfHost"
],
"presentation": {
"hidden": false,
"group": "self-host",
},
"preLaunchTask": "buildAdmin",
},
{
"name": "API Self Host",
"configurations": [
"run-API-SelfHost"
],
"presentation": {
"hidden": false,
"group": "self-host",
},
"preLaunchTask": "buildAPI",
},
{
"name": "Events Processor Self Host",
"configurations": [
"run-EventsProcessor-SelfHost"
],
"presentation": {
"hidden": false,
"group": "self-host",
},
"preLaunchTask": "buildEventsProcessor",
},
{
"name": "Identity Self Host",
"configurations": [
"run-Identity-SelfHost"
],
"presentation": {
"hidden": false,
"group": "self-host",
},
"preLaunchTask": "buildIdentity",
},
{
"name": "Notifications Self Host",
"configurations": [
"run-Notifications-SelfHost"
],
"presentation": {
"hidden": false,
"group": "self-host",
},
"preLaunchTask": "buildNotifications",
},
{
"name": "SSO Self Host",
"configurations": [
"run-Sso-SelfHost"
],
"presentation": {
"hidden": false,
"group": "self-host",
},
"preLaunchTask": "buildSso",
},
],
"configurations": [
// Configurations represent run-only scenarios so that they can be used in multiple compounds
{
"name": "run-Identity",
"presentation": {
"hidden": true,
}, },
"requireExactSource": true, "requireExactSource": true,
"type": "coreclr", "type": "coreclr",
"request": "launch", "request": "launch",
"preLaunchTask": "buildIdentity",
"program": "${workspaceFolder}/src/Identity/bin/Debug/net6.0/Identity.dll", "program": "${workspaceFolder}/src/Identity/bin/Debug/net6.0/Identity.dll",
"args": [], "args": [],
"cwd": "${workspaceFolder}/src/Identity", "cwd": "${workspaceFolder}/src/Identity",
@ -107,16 +264,13 @@
} }
}, },
{ {
"name": "API", "name": "run-API",
"presentation": { "presentation": {
"hidden": false, "hidden": true,
"group": "cloud",
"order": 10
}, },
"requireExactSource": true, "requireExactSource": true,
"type": "coreclr", "type": "coreclr",
"request": "launch", "request": "launch",
"preLaunchTask": "buildAPI",
"program": "${workspaceFolder}/src/Api/bin/Debug/net6.0/Api.dll", "program": "${workspaceFolder}/src/Api/bin/Debug/net6.0/Api.dll",
"args": [], "args": [],
"cwd": "${workspaceFolder}/src/Api", "cwd": "${workspaceFolder}/src/Api",
@ -129,16 +283,13 @@
} }
}, },
{ {
"name": "Billing", "name": "run-Billing",
"presentation": { "presentation": {
"hidden": false, "hidden": true,
"group": "cloud",
"order": 10
}, },
"requireExactSource": true, "requireExactSource": true,
"type": "coreclr", "type": "coreclr",
"request": "launch", "request": "launch",
"preLaunchTask": "buildBilling",
"program": "${workspaceFolder}/src/Billing/bin/Debug/net6.0/Billing.dll", "program": "${workspaceFolder}/src/Billing/bin/Debug/net6.0/Billing.dll",
"args": [], "args": [],
"cwd": "${workspaceFolder}/src/Billing", "cwd": "${workspaceFolder}/src/Billing",
@ -151,16 +302,13 @@
} }
}, },
{ {
"name": "Admin", "name": "run-Admin",
"presentation": { "presentation": {
"hidden": false, "hidden": true,
"group": "cloud",
"order": 20
}, },
"requireExactSource": true, "requireExactSource": true,
"type": "coreclr", "type": "coreclr",
"request": "launch", "request": "launch",
"preLaunchTask": "buildAdmin",
"OS-COMMENT4": "If you have changed target frameworks, make sure to update the program path.", "OS-COMMENT4": "If you have changed target frameworks, make sure to update the program path.",
"program": "${workspaceFolder}/src/Admin/bin/Debug/net6.0/Admin.dll", "program": "${workspaceFolder}/src/Admin/bin/Debug/net6.0/Admin.dll",
"args": [], "args": [],
@ -175,16 +323,13 @@
} }
}, },
{ {
"name": "Sso", "name": "run-Sso",
"presentation": { "presentation": {
"hidden": false, "hidden": true,
"group": "cloud",
"order": 50
}, },
"requireExactSource": true, "requireExactSource": true,
"type": "coreclr", "type": "coreclr",
"request": "launch", "request": "launch",
"preLaunchTask": "buildSso",
"program": "${workspaceFolder}/bitwarden_license/src/Sso/bin/Debug/net6.0/Sso.dll", "program": "${workspaceFolder}/bitwarden_license/src/Sso/bin/Debug/net6.0/Sso.dll",
"args": [], "args": [],
"cwd": "${workspaceFolder}/bitwarden_license/src/Sso", "cwd": "${workspaceFolder}/bitwarden_license/src/Sso",
@ -197,16 +342,13 @@
} }
}, },
{ {
"name": "EventsProcessor", "name": "run-EventsProcessor",
"presentation": { "presentation": {
"hidden": false, "hidden": true,
"group": "cloud",
"order": 90
}, },
"requireExactSource": true, "requireExactSource": true,
"type": "coreclr", "type": "coreclr",
"request": "launch", "request": "launch",
"preLaunchTask": "buildEventsProcessor",
"program": "${workspaceFolder}/src/EventsProcessor/bin/Debug/net6.0/EventsProcessor.dll", "program": "${workspaceFolder}/src/EventsProcessor/bin/Debug/net6.0/EventsProcessor.dll",
"args": [], "args": [],
"cwd": "${workspaceFolder}/src/EventsProcessor", "cwd": "${workspaceFolder}/src/EventsProcessor",
@ -219,16 +361,13 @@
} }
}, },
{ {
"name": "Icons", "name": "run-Icons",
"presentation": { "presentation": {
"hidden": false, "hidden": true,
"group": "cloud",
"order": 90
}, },
"requireExactSource": true, "requireExactSource": true,
"type": "coreclr", "type": "coreclr",
"request": "launch", "request": "launch",
"preLaunchTask": "buildIcons",
"program": "${workspaceFolder}/src/Icons/bin/Debug/net6.0/Icons.dll", "program": "${workspaceFolder}/src/Icons/bin/Debug/net6.0/Icons.dll",
"args": [], "args": [],
"cwd": "${workspaceFolder}/src/Icons", "cwd": "${workspaceFolder}/src/Icons",
@ -241,16 +380,13 @@
} }
}, },
{ {
"name": "Notifications", "name": "run-Notifications",
"presentation": { "presentation": {
"hidden": true, "hidden": true,
"group": "cloud",
"order": 100
}, },
"requireExactSource": true, "requireExactSource": true,
"type": "coreclr", "type": "coreclr",
"request": "launch", "request": "launch",
"preLaunchTask": "buildNotifications",
"program": "${workspaceFolder}/src/Notifications/bin/Debug/net6.0/Notifications.dll", "program": "${workspaceFolder}/src/Notifications/bin/Debug/net6.0/Notifications.dll",
"args": [], "args": [],
"cwd": "${workspaceFolder}/src/Notifications", "cwd": "${workspaceFolder}/src/Notifications",
@ -263,16 +399,13 @@
} }
}, },
{ {
"name": "Identity-SelfHost", "name": "run-Identity-SelfHost",
"presentation": { "presentation": {
"hidden": true, "hidden": true,
"group": "self-host",
"order": 999
}, },
"requireExactSource": true, "requireExactSource": true,
"type": "coreclr", "type": "coreclr",
"request": "launch", "request": "launch",
"preLaunchTask": "buildIdentity",
"program": "${workspaceFolder}/src/Identity/bin/Debug/net6.0/Identity.dll", "program": "${workspaceFolder}/src/Identity/bin/Debug/net6.0/Identity.dll",
"args": [], "args": [],
"cwd": "${workspaceFolder}/src/Identity", "cwd": "${workspaceFolder}/src/Identity",
@ -287,16 +420,13 @@
} }
}, },
{ {
"name": "API-SelfHost", "name": "run-API-SelfHost",
"presentation": { "presentation": {
"hidden": true, "hidden": true,
"group": "self-host",
"order": 999
}, },
"requireExactSource": true, "requireExactSource": true,
"type": "coreclr", "type": "coreclr",
"request": "launch", "request": "launch",
"preLaunchTask": "buildAPI",
"program": "${workspaceFolder}/src/Api/bin/Debug/net6.0/Api.dll", "program": "${workspaceFolder}/src/Api/bin/Debug/net6.0/Api.dll",
"args": [], "args": [],
"cwd": "${workspaceFolder}/src/Api", "cwd": "${workspaceFolder}/src/Api",
@ -311,16 +441,13 @@
} }
}, },
{ {
"name": "Admin-SelfHost", "name": "run-Admin-SelfHost",
"presentation": { "presentation": {
"hidden": true, "hidden": true,
"group": "self-host",
"order": 999
}, },
"requireExactSource": true, "requireExactSource": true,
"type": "coreclr", "type": "coreclr",
"request": "launch", "request": "launch",
"preLaunchTask": "buildAdmin",
"OS-COMMENT4": "If you have changed target frameworks, make sure to update the program path.", "OS-COMMENT4": "If you have changed target frameworks, make sure to update the program path.",
"program": "${workspaceFolder}/src/Admin/bin/Debug/net6.0/Admin.dll", "program": "${workspaceFolder}/src/Admin/bin/Debug/net6.0/Admin.dll",
"args": [], "args": [],
@ -337,16 +464,13 @@
} }
}, },
{ {
"name": "Sso-SelfHost", "name": "run-Sso-SelfHost",
"presentation": { "presentation": {
"hidden": true, "hidden": true,
"group": "self-host",
"order": 999
}, },
"requireExactSource": true, "requireExactSource": true,
"type": "coreclr", "type": "coreclr",
"request": "launch", "request": "launch",
"preLaunchTask": "buildSso",
"program": "${workspaceFolder}/bitwarden_license/src/Sso/bin/Debug/net6.0/Sso.dll", "program": "${workspaceFolder}/bitwarden_license/src/Sso/bin/Debug/net6.0/Sso.dll",
"args": [], "args": [],
"cwd": "${workspaceFolder}/bitwarden_license/src/Sso", "cwd": "${workspaceFolder}/bitwarden_license/src/Sso",
@ -361,16 +485,13 @@
} }
}, },
{ {
"name": "Notifications-SelfHost", "name": "run-Notifications-SelfHost",
"presentation": { "presentation": {
"hidden": true, "hidden": true,
"group": "self-host",
"order": 999
}, },
"requireExactSource": true, "requireExactSource": true,
"type": "coreclr", "type": "coreclr",
"request": "launch", "request": "launch",
"preLaunchTask": "buildNotifications",
"program": "${workspaceFolder}/src/Notifications/bin/Debug/net6.0/Notifications.dll", "program": "${workspaceFolder}/src/Notifications/bin/Debug/net6.0/Notifications.dll",
"args": [], "args": [],
"cwd": "${workspaceFolder}/src/Notifications", "cwd": "${workspaceFolder}/src/Notifications",
@ -385,16 +506,13 @@
} }
}, },
{ {
"name": "EventsProcessor-SelfHost", "name": "run-EventsProcessor-SelfHost",
"presentation": { "presentation": {
"hidden": true, "hidden": true,
"group": "self-host",
"order": 999
}, },
"requireExactSource": true, "requireExactSource": true,
"type": "coreclr", "type": "coreclr",
"request": "launch", "request": "launch",
"preLaunchTask": "buildEventsProcessor",
"program": "${workspaceFolder}/src/EventsProcessor/bin/Debug/net6.0/EventsProcessor.dll", "program": "${workspaceFolder}/src/EventsProcessor/bin/Debug/net6.0/EventsProcessor.dll",
"args": [], "args": [],
"cwd": "${workspaceFolder}/src/EventsProcessor", "cwd": "${workspaceFolder}/src/EventsProcessor",

59
.vscode/tasks.json vendored
View File

@ -1,6 +1,65 @@
{ {
"version": "2.0.0", "version": "2.0.0",
"tasks": [ "tasks": [
{
"label": "buildIdentityApi",
"dependsOrder": "sequence",
"dependsOn": [
"buildIdentity",
"buildAPI"
],
"problemMatcher": [
"$msCompile"
]
},
{
"label": "buildIdentityApiAdmin",
"dependsOrder": "sequence",
"dependsOn": [
"buildIdentity",
"buildAPI",
"buildAdmin"
],
"problemMatcher": [
"$msCompile"
]
},
{
"label": "buildFullServer",
"dependsOrder": "sequence",
"dependsOn": [
"buildAdmin",
"buildAPI",
"buildEventsProcessor",
"buildIdentity",
"buildSso",
"buildIcons",
"buildBilling",
"buildNotifications",
],
},
{
"label": "buildSelfHostBit",
"dependsOrder": "sequence",
"dependsOn": [
"buildAdmin",
"buildAPI",
"buildEventsProcessor",
"buildIdentity",
"buildSso",
"buildNotifications",
],
},
{
"label": "buildSelfHostOss",
"dependsOrder": "sequence",
"dependsOn": [
"buildAdmin",
"buildAPI",
"buildEventsProcessor",
"buildIdentity",
],
},
{ {
"label": "buildIcons", "label": "buildIcons",
"command": "dotnet", "command": "dotnet",

View File

@ -2,7 +2,7 @@
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
<Version>2023.10.2</Version> <Version>2023.10.3</Version>
<RootNamespace>Bit.$(MSBuildProjectName)</RootNamespace> <RootNamespace>Bit.$(MSBuildProjectName)</RootNamespace>
<RestorePackagesWithLockFile>true</RestorePackagesWithLockFile> <RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>

View File

@ -162,6 +162,24 @@
"Microsoft.Win32.Registry": "5.0.0" "Microsoft.Win32.Registry": "5.0.0"
} }
}, },
"Duende.IdentityServer": {
"type": "Transitive",
"resolved": "6.0.4",
"contentHash": "4HVjzx1F8v5J+U7oa8RGAQGj2QzmzNSu87r18Sh+dlh10uyZZL8teAaT/FaVLDObnfItGdPFvN8mwpF/HkI3Xw==",
"dependencies": {
"Duende.IdentityServer.Storage": "6.0.4",
"Microsoft.AspNetCore.Authentication.OpenIdConnect": "6.0.0"
}
},
"Duende.IdentityServer.Storage": {
"type": "Transitive",
"resolved": "6.0.4",
"contentHash": "s5gAjfbpr2IMgI+fU2Nx+2AZdzstmbt9gpo13iX7GwvqSeSaBVqj9ZskAN0R2KF1OemPdZuGnfaTcevdXMUrrw==",
"dependencies": {
"IdentityModel": "6.0.0",
"Microsoft.AspNetCore.DataProtection.Abstractions": "6.0.0"
}
},
"Fido2": { "Fido2": {
"type": "Transitive", "type": "Transitive",
"resolved": "3.0.1", "resolved": "3.0.1",
@ -198,49 +216,8 @@
}, },
"IdentityModel": { "IdentityModel": {
"type": "Transitive", "type": "Transitive",
"resolved": "4.4.0", "resolved": "6.0.0",
"contentHash": "b18wrIx5wnZlMxAX7oVsE+nDtAJ4hajYlH0xPlaRvo4r/fz08K6pPeZvbiqS9nfNbzfIgLFmNX+FL9qR9ZR5PA==", "contentHash": "eVHCR7a6m/dm5RFcBzE3qs/Jg5j9R5Rjpu8aTOv9e4AFvaQtBXb5ah7kmwU+YwA0ufRwz4wf1hnIvsD2hSnI4g=="
"dependencies": {
"Newtonsoft.Json": "11.0.2",
"System.Text.Encodings.Web": "4.7.0"
}
},
"IdentityModel.AspNetCore.OAuth2Introspection": {
"type": "Transitive",
"resolved": "4.0.1",
"contentHash": "ZNdMZMaj9fqR3j50vYsu+1U3QGd6n8+fqwf+a8mCTcmXGor+HgFDfdq0mM34bsmD6uEgAQup7sv2ZW5kR36dbA==",
"dependencies": {
"IdentityModel": "4.0.0"
}
},
"IdentityServer4": {
"type": "Transitive",
"resolved": "4.1.2",
"contentHash": "blaxxGuOA7v/w1q+fxn97wZ+x2ecG1ZD4mc/N/ZOXMNeFZZhqv+4LF26Gecyik3nWrJPmbMEtQbLmRsKG8k61w==",
"dependencies": {
"IdentityModel": "4.4.0",
"IdentityServer4.Storage": "4.1.2",
"Microsoft.AspNetCore.Authentication.OpenIdConnect": "3.1.0",
"Microsoft.IdentityModel.Protocols.OpenIdConnect": "5.6.0",
"Newtonsoft.Json": "12.0.2"
}
},
"IdentityServer4.AccessTokenValidation": {
"type": "Transitive",
"resolved": "3.0.1",
"contentHash": "qu/M6UyN4o9NVep7q545Ms7hYAnsQqSdLbN1Fjjrn4m35lyBfeQPSSNzDryAKHbodyWOQfHaOqKEyMEJQ5Rpgw==",
"dependencies": {
"IdentityModel.AspNetCore.OAuth2Introspection": "4.0.1",
"Microsoft.AspNetCore.Authentication.JwtBearer": "3.0.0"
}
},
"IdentityServer4.Storage": {
"type": "Transitive",
"resolved": "4.1.2",
"contentHash": "KoSffyZyyeCNTIyJiZnCuPakJ1QbCHlpty6gbWUj/7yl+w0PXIchgmmJnJSvddzBb8iZ2xew/vGlxWUIP17P2g==",
"dependencies": {
"IdentityModel": "4.4.0"
}
}, },
"LaunchDarkly.Cache": { "LaunchDarkly.Cache": {
"type": "Transitive", "type": "Transitive",
@ -318,10 +295,10 @@
}, },
"Microsoft.AspNetCore.Authentication.OpenIdConnect": { "Microsoft.AspNetCore.Authentication.OpenIdConnect": {
"type": "Transitive", "type": "Transitive",
"resolved": "3.1.0", "resolved": "6.0.0",
"contentHash": "O1cAQYUTU8EfRqwc5/rfTns4E4hKlFlg59fuKRrST+PzsxI6H07KqRN/JjdYhAuVYxF8jPnIGbj+zuc5paOWUw==", "contentHash": "cJxdro36spFzk/K2OFCddM6vZ+yoj6ug8mTFRH3Gdv1Pul/buSuCtfb/FSCp31UmS5S4C1315dU7wX3ErLFuDg==",
"dependencies": { "dependencies": {
"Microsoft.IdentityModel.Protocols.OpenIdConnect": "5.5.0" "Microsoft.IdentityModel.Protocols.OpenIdConnect": "6.10.0"
} }
}, },
"Microsoft.AspNetCore.Cryptography.Internal": { "Microsoft.AspNetCore.Cryptography.Internal": {
@ -354,8 +331,8 @@
}, },
"Microsoft.AspNetCore.DataProtection.Abstractions": { "Microsoft.AspNetCore.DataProtection.Abstractions": {
"type": "Transitive", "type": "Transitive",
"resolved": "3.1.32", "resolved": "6.0.0",
"contentHash": "MPL4iVyiaRxnOUY5VATHjvhDWaAEFb77KFiUxVRklv3Z3v+STofUr1UG/aCt1O9cgN7FVTDaC5A7U+zsLub8Xg==" "contentHash": "Z/UU4NEBm5UgNufJmw+j5baW26ytCOIZ0G7sZocPaOzsUeBon1bkM3lSMNZQG2GmDjAIVP2XMSODf2jzSGbibw=="
}, },
"Microsoft.Azure.Amqp": { "Microsoft.Azure.Amqp": {
"type": "Transitive", "type": "Transitive",
@ -2450,10 +2427,9 @@
"BitPay.Light": "[1.0.1907, )", "BitPay.Light": "[1.0.1907, )",
"Braintree": "[5.19.0, )", "Braintree": "[5.19.0, )",
"DnsClient": "[1.7.0, )", "DnsClient": "[1.7.0, )",
"Duende.IdentityServer": "[6.0.4, )",
"Fido2.AspNet": "[3.0.1, )", "Fido2.AspNet": "[3.0.1, )",
"Handlebars.Net": "[2.1.2, )", "Handlebars.Net": "[2.1.2, )",
"IdentityServer4": "[4.1.2, )",
"IdentityServer4.AccessTokenValidation": "[3.0.1, )",
"LaunchDarkly.ServerSdk": "[8.0.0, )", "LaunchDarkly.ServerSdk": "[8.0.0, )",
"MailKit": "[4.2.0, )", "MailKit": "[4.2.0, )",
"Microsoft.AspNetCore.Authentication.JwtBearer": "[6.0.4, )", "Microsoft.AspNetCore.Authentication.JwtBearer": "[6.0.4, )",

View File

@ -180,6 +180,24 @@
"Microsoft.Win32.Registry": "5.0.0" "Microsoft.Win32.Registry": "5.0.0"
} }
}, },
"Duende.IdentityServer": {
"type": "Transitive",
"resolved": "6.0.4",
"contentHash": "4HVjzx1F8v5J+U7oa8RGAQGj2QzmzNSu87r18Sh+dlh10uyZZL8teAaT/FaVLDObnfItGdPFvN8mwpF/HkI3Xw==",
"dependencies": {
"Duende.IdentityServer.Storage": "6.0.4",
"Microsoft.AspNetCore.Authentication.OpenIdConnect": "6.0.0"
}
},
"Duende.IdentityServer.Storage": {
"type": "Transitive",
"resolved": "6.0.4",
"contentHash": "s5gAjfbpr2IMgI+fU2Nx+2AZdzstmbt9gpo13iX7GwvqSeSaBVqj9ZskAN0R2KF1OemPdZuGnfaTcevdXMUrrw==",
"dependencies": {
"IdentityModel": "6.0.0",
"Microsoft.AspNetCore.DataProtection.Abstractions": "6.0.0"
}
},
"Fido2": { "Fido2": {
"type": "Transitive", "type": "Transitive",
"resolved": "3.0.1", "resolved": "3.0.1",
@ -216,49 +234,8 @@
}, },
"IdentityModel": { "IdentityModel": {
"type": "Transitive", "type": "Transitive",
"resolved": "4.4.0", "resolved": "6.0.0",
"contentHash": "b18wrIx5wnZlMxAX7oVsE+nDtAJ4hajYlH0xPlaRvo4r/fz08K6pPeZvbiqS9nfNbzfIgLFmNX+FL9qR9ZR5PA==", "contentHash": "eVHCR7a6m/dm5RFcBzE3qs/Jg5j9R5Rjpu8aTOv9e4AFvaQtBXb5ah7kmwU+YwA0ufRwz4wf1hnIvsD2hSnI4g=="
"dependencies": {
"Newtonsoft.Json": "11.0.2",
"System.Text.Encodings.Web": "4.7.0"
}
},
"IdentityModel.AspNetCore.OAuth2Introspection": {
"type": "Transitive",
"resolved": "4.0.1",
"contentHash": "ZNdMZMaj9fqR3j50vYsu+1U3QGd6n8+fqwf+a8mCTcmXGor+HgFDfdq0mM34bsmD6uEgAQup7sv2ZW5kR36dbA==",
"dependencies": {
"IdentityModel": "4.0.0"
}
},
"IdentityServer4": {
"type": "Transitive",
"resolved": "4.1.2",
"contentHash": "blaxxGuOA7v/w1q+fxn97wZ+x2ecG1ZD4mc/N/ZOXMNeFZZhqv+4LF26Gecyik3nWrJPmbMEtQbLmRsKG8k61w==",
"dependencies": {
"IdentityModel": "4.4.0",
"IdentityServer4.Storage": "4.1.2",
"Microsoft.AspNetCore.Authentication.OpenIdConnect": "3.1.0",
"Microsoft.IdentityModel.Protocols.OpenIdConnect": "5.6.0",
"Newtonsoft.Json": "12.0.2"
}
},
"IdentityServer4.AccessTokenValidation": {
"type": "Transitive",
"resolved": "3.0.1",
"contentHash": "qu/M6UyN4o9NVep7q545Ms7hYAnsQqSdLbN1Fjjrn4m35lyBfeQPSSNzDryAKHbodyWOQfHaOqKEyMEJQ5Rpgw==",
"dependencies": {
"IdentityModel.AspNetCore.OAuth2Introspection": "4.0.1",
"Microsoft.AspNetCore.Authentication.JwtBearer": "3.0.0"
}
},
"IdentityServer4.Storage": {
"type": "Transitive",
"resolved": "4.1.2",
"contentHash": "KoSffyZyyeCNTIyJiZnCuPakJ1QbCHlpty6gbWUj/7yl+w0PXIchgmmJnJSvddzBb8iZ2xew/vGlxWUIP17P2g==",
"dependencies": {
"IdentityModel": "4.4.0"
}
}, },
"LaunchDarkly.Cache": { "LaunchDarkly.Cache": {
"type": "Transitive", "type": "Transitive",
@ -350,10 +327,10 @@
}, },
"Microsoft.AspNetCore.Authentication.OpenIdConnect": { "Microsoft.AspNetCore.Authentication.OpenIdConnect": {
"type": "Transitive", "type": "Transitive",
"resolved": "3.1.0", "resolved": "6.0.0",
"contentHash": "O1cAQYUTU8EfRqwc5/rfTns4E4hKlFlg59fuKRrST+PzsxI6H07KqRN/JjdYhAuVYxF8jPnIGbj+zuc5paOWUw==", "contentHash": "cJxdro36spFzk/K2OFCddM6vZ+yoj6ug8mTFRH3Gdv1Pul/buSuCtfb/FSCp31UmS5S4C1315dU7wX3ErLFuDg==",
"dependencies": { "dependencies": {
"Microsoft.IdentityModel.Protocols.OpenIdConnect": "5.5.0" "Microsoft.IdentityModel.Protocols.OpenIdConnect": "6.10.0"
} }
}, },
"Microsoft.AspNetCore.Cryptography.Internal": { "Microsoft.AspNetCore.Cryptography.Internal": {
@ -386,8 +363,8 @@
}, },
"Microsoft.AspNetCore.DataProtection.Abstractions": { "Microsoft.AspNetCore.DataProtection.Abstractions": {
"type": "Transitive", "type": "Transitive",
"resolved": "3.1.32", "resolved": "6.0.0",
"contentHash": "MPL4iVyiaRxnOUY5VATHjvhDWaAEFb77KFiUxVRklv3Z3v+STofUr1UG/aCt1O9cgN7FVTDaC5A7U+zsLub8Xg==" "contentHash": "Z/UU4NEBm5UgNufJmw+j5baW26ytCOIZ0G7sZocPaOzsUeBon1bkM3lSMNZQG2GmDjAIVP2XMSODf2jzSGbibw=="
}, },
"Microsoft.Azure.Amqp": { "Microsoft.Azure.Amqp": {
"type": "Transitive", "type": "Transitive",
@ -2613,10 +2590,9 @@
"BitPay.Light": "[1.0.1907, )", "BitPay.Light": "[1.0.1907, )",
"Braintree": "[5.19.0, )", "Braintree": "[5.19.0, )",
"DnsClient": "[1.7.0, )", "DnsClient": "[1.7.0, )",
"Duende.IdentityServer": "[6.0.4, )",
"Fido2.AspNet": "[3.0.1, )", "Fido2.AspNet": "[3.0.1, )",
"Handlebars.Net": "[2.1.2, )", "Handlebars.Net": "[2.1.2, )",
"IdentityServer4": "[4.1.2, )",
"IdentityServer4.AccessTokenValidation": "[3.0.1, )",
"LaunchDarkly.ServerSdk": "[8.0.0, )", "LaunchDarkly.ServerSdk": "[8.0.0, )",
"MailKit": "[4.2.0, )", "MailKit": "[4.2.0, )",
"Microsoft.AspNetCore.Authentication.JwtBearer": "[6.0.4, )", "Microsoft.AspNetCore.Authentication.JwtBearer": "[6.0.4, )",
@ -2645,7 +2621,7 @@
"type": "Project", "type": "Project",
"dependencies": { "dependencies": {
"AutoMapper.Extensions.Microsoft.DependencyInjection": "[12.0.1, )", "AutoMapper.Extensions.Microsoft.DependencyInjection": "[12.0.1, )",
"Core": "[2023.10.2, )", "Core": "[2023.10.3, )",
"Microsoft.EntityFrameworkCore.Relational": "[7.0.5, )", "Microsoft.EntityFrameworkCore.Relational": "[7.0.5, )",
"Microsoft.EntityFrameworkCore.SqlServer": "[7.0.5, )", "Microsoft.EntityFrameworkCore.SqlServer": "[7.0.5, )",
"Microsoft.EntityFrameworkCore.Sqlite": "[7.0.5, )", "Microsoft.EntityFrameworkCore.Sqlite": "[7.0.5, )",

View File

@ -184,6 +184,24 @@
"Microsoft.Win32.Registry": "5.0.0" "Microsoft.Win32.Registry": "5.0.0"
} }
}, },
"Duende.IdentityServer": {
"type": "Transitive",
"resolved": "6.0.4",
"contentHash": "4HVjzx1F8v5J+U7oa8RGAQGj2QzmzNSu87r18Sh+dlh10uyZZL8teAaT/FaVLDObnfItGdPFvN8mwpF/HkI3Xw==",
"dependencies": {
"Duende.IdentityServer.Storage": "6.0.4",
"Microsoft.AspNetCore.Authentication.OpenIdConnect": "6.0.0"
}
},
"Duende.IdentityServer.Storage": {
"type": "Transitive",
"resolved": "6.0.4",
"contentHash": "s5gAjfbpr2IMgI+fU2Nx+2AZdzstmbt9gpo13iX7GwvqSeSaBVqj9ZskAN0R2KF1OemPdZuGnfaTcevdXMUrrw==",
"dependencies": {
"IdentityModel": "6.0.0",
"Microsoft.AspNetCore.DataProtection.Abstractions": "6.0.0"
}
},
"Fido2": { "Fido2": {
"type": "Transitive", "type": "Transitive",
"resolved": "3.0.1", "resolved": "3.0.1",
@ -220,49 +238,8 @@
}, },
"IdentityModel": { "IdentityModel": {
"type": "Transitive", "type": "Transitive",
"resolved": "4.4.0", "resolved": "6.0.0",
"contentHash": "b18wrIx5wnZlMxAX7oVsE+nDtAJ4hajYlH0xPlaRvo4r/fz08K6pPeZvbiqS9nfNbzfIgLFmNX+FL9qR9ZR5PA==", "contentHash": "eVHCR7a6m/dm5RFcBzE3qs/Jg5j9R5Rjpu8aTOv9e4AFvaQtBXb5ah7kmwU+YwA0ufRwz4wf1hnIvsD2hSnI4g=="
"dependencies": {
"Newtonsoft.Json": "11.0.2",
"System.Text.Encodings.Web": "4.7.0"
}
},
"IdentityModel.AspNetCore.OAuth2Introspection": {
"type": "Transitive",
"resolved": "4.0.1",
"contentHash": "ZNdMZMaj9fqR3j50vYsu+1U3QGd6n8+fqwf+a8mCTcmXGor+HgFDfdq0mM34bsmD6uEgAQup7sv2ZW5kR36dbA==",
"dependencies": {
"IdentityModel": "4.0.0"
}
},
"IdentityServer4": {
"type": "Transitive",
"resolved": "4.1.2",
"contentHash": "blaxxGuOA7v/w1q+fxn97wZ+x2ecG1ZD4mc/N/ZOXMNeFZZhqv+4LF26Gecyik3nWrJPmbMEtQbLmRsKG8k61w==",
"dependencies": {
"IdentityModel": "4.4.0",
"IdentityServer4.Storage": "4.1.2",
"Microsoft.AspNetCore.Authentication.OpenIdConnect": "3.1.0",
"Microsoft.IdentityModel.Protocols.OpenIdConnect": "5.6.0",
"Newtonsoft.Json": "12.0.2"
}
},
"IdentityServer4.AccessTokenValidation": {
"type": "Transitive",
"resolved": "3.0.1",
"contentHash": "qu/M6UyN4o9NVep7q545Ms7hYAnsQqSdLbN1Fjjrn4m35lyBfeQPSSNzDryAKHbodyWOQfHaOqKEyMEJQ5Rpgw==",
"dependencies": {
"IdentityModel.AspNetCore.OAuth2Introspection": "4.0.1",
"Microsoft.AspNetCore.Authentication.JwtBearer": "3.0.0"
}
},
"IdentityServer4.Storage": {
"type": "Transitive",
"resolved": "4.1.2",
"contentHash": "KoSffyZyyeCNTIyJiZnCuPakJ1QbCHlpty6gbWUj/7yl+w0PXIchgmmJnJSvddzBb8iZ2xew/vGlxWUIP17P2g==",
"dependencies": {
"IdentityModel": "4.4.0"
}
}, },
"LaunchDarkly.Cache": { "LaunchDarkly.Cache": {
"type": "Transitive", "type": "Transitive",
@ -354,10 +331,10 @@
}, },
"Microsoft.AspNetCore.Authentication.OpenIdConnect": { "Microsoft.AspNetCore.Authentication.OpenIdConnect": {
"type": "Transitive", "type": "Transitive",
"resolved": "3.1.0", "resolved": "6.0.0",
"contentHash": "O1cAQYUTU8EfRqwc5/rfTns4E4hKlFlg59fuKRrST+PzsxI6H07KqRN/JjdYhAuVYxF8jPnIGbj+zuc5paOWUw==", "contentHash": "cJxdro36spFzk/K2OFCddM6vZ+yoj6ug8mTFRH3Gdv1Pul/buSuCtfb/FSCp31UmS5S4C1315dU7wX3ErLFuDg==",
"dependencies": { "dependencies": {
"Microsoft.IdentityModel.Protocols.OpenIdConnect": "5.5.0" "Microsoft.IdentityModel.Protocols.OpenIdConnect": "6.10.0"
} }
}, },
"Microsoft.AspNetCore.Cryptography.Internal": { "Microsoft.AspNetCore.Cryptography.Internal": {
@ -390,8 +367,8 @@
}, },
"Microsoft.AspNetCore.DataProtection.Abstractions": { "Microsoft.AspNetCore.DataProtection.Abstractions": {
"type": "Transitive", "type": "Transitive",
"resolved": "3.1.32", "resolved": "6.0.0",
"contentHash": "MPL4iVyiaRxnOUY5VATHjvhDWaAEFb77KFiUxVRklv3Z3v+STofUr1UG/aCt1O9cgN7FVTDaC5A7U+zsLub8Xg==" "contentHash": "Z/UU4NEBm5UgNufJmw+j5baW26ytCOIZ0G7sZocPaOzsUeBon1bkM3lSMNZQG2GmDjAIVP2XMSODf2jzSGbibw=="
}, },
"Microsoft.Azure.Amqp": { "Microsoft.Azure.Amqp": {
"type": "Transitive", "type": "Transitive",
@ -2617,10 +2594,9 @@
"BitPay.Light": "[1.0.1907, )", "BitPay.Light": "[1.0.1907, )",
"Braintree": "[5.19.0, )", "Braintree": "[5.19.0, )",
"DnsClient": "[1.7.0, )", "DnsClient": "[1.7.0, )",
"Duende.IdentityServer": "[6.0.4, )",
"Fido2.AspNet": "[3.0.1, )", "Fido2.AspNet": "[3.0.1, )",
"Handlebars.Net": "[2.1.2, )", "Handlebars.Net": "[2.1.2, )",
"IdentityServer4": "[4.1.2, )",
"IdentityServer4.AccessTokenValidation": "[3.0.1, )",
"LaunchDarkly.ServerSdk": "[8.0.0, )", "LaunchDarkly.ServerSdk": "[8.0.0, )",
"MailKit": "[4.2.0, )", "MailKit": "[4.2.0, )",
"Microsoft.AspNetCore.Authentication.JwtBearer": "[6.0.4, )", "Microsoft.AspNetCore.Authentication.JwtBearer": "[6.0.4, )",
@ -2648,7 +2624,7 @@
"infrastructure.dapper": { "infrastructure.dapper": {
"type": "Project", "type": "Project",
"dependencies": { "dependencies": {
"Core": "[2023.10.2, )", "Core": "[2023.10.3, )",
"Dapper": "[2.0.123, )" "Dapper": "[2.0.123, )"
} }
}, },
@ -2656,7 +2632,7 @@
"type": "Project", "type": "Project",
"dependencies": { "dependencies": {
"AutoMapper.Extensions.Microsoft.DependencyInjection": "[12.0.1, )", "AutoMapper.Extensions.Microsoft.DependencyInjection": "[12.0.1, )",
"Core": "[2023.10.2, )", "Core": "[2023.10.3, )",
"Microsoft.EntityFrameworkCore.Relational": "[7.0.5, )", "Microsoft.EntityFrameworkCore.Relational": "[7.0.5, )",
"Microsoft.EntityFrameworkCore.SqlServer": "[7.0.5, )", "Microsoft.EntityFrameworkCore.SqlServer": "[7.0.5, )",
"Microsoft.EntityFrameworkCore.Sqlite": "[7.0.5, )", "Microsoft.EntityFrameworkCore.Sqlite": "[7.0.5, )",
@ -2668,9 +2644,9 @@
"sharedweb": { "sharedweb": {
"type": "Project", "type": "Project",
"dependencies": { "dependencies": {
"Core": "[2023.10.2, )", "Core": "[2023.10.3, )",
"Infrastructure.Dapper": "[2023.10.2, )", "Infrastructure.Dapper": "[2023.10.3, )",
"Infrastructure.EntityFramework": "[2023.10.2, )" "Infrastructure.EntityFramework": "[2023.10.3, )"
} }
} }
} }

View File

@ -1,5 +1,7 @@
using System.Security.Claims; using System.Security.Claims;
using Bit.Core; using Bit.Core;
using Bit.Core.AdminConsole.Enums;
using Bit.Core.AdminConsole.Repositories;
using Bit.Core.Auth.Entities; using Bit.Core.Auth.Entities;
using Bit.Core.Auth.Enums; using Bit.Core.Auth.Enums;
using Bit.Core.Auth.Models; using Bit.Core.Auth.Models;
@ -16,14 +18,15 @@ using Bit.Core.Tokens;
using Bit.Core.Utilities; using Bit.Core.Utilities;
using Bit.Sso.Models; using Bit.Sso.Models;
using Bit.Sso.Utilities; using Bit.Sso.Utilities;
using Duende.IdentityServer;
using Duende.IdentityServer.Extensions;
using Duende.IdentityServer.Services;
using Duende.IdentityServer.Stores;
using IdentityModel; using IdentityModel;
using IdentityServer4;
using IdentityServer4.Extensions;
using IdentityServer4.Services;
using IdentityServer4.Stores;
using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using DIM = Duende.IdentityServer.Models;
namespace Bit.Sso.Controllers; namespace Bit.Sso.Controllers;
@ -717,7 +720,7 @@ public class AccountController : Controller
return (logoutId, logout?.PostLogoutRedirectUri, externalAuthenticationScheme); return (logoutId, logout?.PostLogoutRedirectUri, externalAuthenticationScheme);
} }
public bool IsNativeClient(IdentityServer4.Models.AuthorizationRequest context) public bool IsNativeClient(DIM.AuthorizationRequest context)
{ {
return !context.RedirectUri.StartsWith("https", StringComparison.Ordinal) return !context.RedirectUri.StartsWith("https", StringComparison.Ordinal)
&& !context.RedirectUri.StartsWith("http", StringComparison.Ordinal); && !context.RedirectUri.StartsWith("http", StringComparison.Ordinal);

View File

@ -1,6 +1,6 @@
using System.Diagnostics; using System.Diagnostics;
using Bit.Sso.Models; using Bit.Sso.Models;
using IdentityServer4.Services; using Duende.IdentityServer.Services;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Diagnostics; using Microsoft.AspNetCore.Diagnostics;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;

View File

@ -1,6 +1,6 @@
using Bit.Core.Settings; using Bit.Core.Settings;
using IdentityServer4; using Duende.IdentityServer;
using IdentityServer4.Models; using Duende.IdentityServer.Models;
namespace Bit.Sso.IdentityServer; namespace Bit.Sso.IdentityServer;

View File

@ -1,4 +1,4 @@
using IdentityServer4.Models; using Duende.IdentityServer.Models;
namespace Bit.Sso.Models; namespace Bit.Sso.Models;

View File

@ -6,7 +6,7 @@ using Bit.Core.Settings;
using Bit.Core.Utilities; using Bit.Core.Utilities;
using Bit.SharedWeb.Utilities; using Bit.SharedWeb.Utilities;
using Bit.Sso.Utilities; using Bit.Sso.Utilities;
using IdentityServer4.Extensions; using Duende.IdentityServer.Extensions;
using Microsoft.IdentityModel.Logging; using Microsoft.IdentityModel.Logging;
using Stripe; using Stripe;

View File

@ -1,13 +1,14 @@
using Bit.Core.Settings; using Bit.Core.Settings;
using Bit.Core.Utilities; using Bit.Core.Utilities;
using IdentityServer4.Configuration; using Duende.IdentityServer.Configuration;
using IdentityServer4.Services; using Duende.IdentityServer.Services;
using IdentityServer4.Stores; using Duende.IdentityServer.Stores;
using IdentityServer4.Validation; using Duende.IdentityServer.Validation;
using DIR = Duende.IdentityServer.ResponseHandling;
namespace Bit.Sso.Utilities; namespace Bit.Sso.Utilities;
public class DiscoveryResponseGenerator : IdentityServer4.ResponseHandling.DiscoveryResponseGenerator public class DiscoveryResponseGenerator : DIR.DiscoveryResponseGenerator
{ {
private readonly GlobalSettings _globalSettings; private readonly GlobalSettings _globalSettings;

View File

@ -7,9 +7,9 @@ using Bit.Core.Settings;
using Bit.Core.Utilities; using Bit.Core.Utilities;
using Bit.Sso.Models; using Bit.Sso.Models;
using Bit.Sso.Utilities; using Bit.Sso.Utilities;
using Duende.IdentityServer;
using Duende.IdentityServer.Infrastructure;
using IdentityModel; using IdentityModel;
using IdentityServer4;
using IdentityServer4.Infrastructure;
using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.OpenIdConnect; using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
@ -34,7 +34,7 @@ public class DynamicAuthenticationSchemeProvider : AuthenticationSchemeProvider
private readonly Dictionary<string, DynamicAuthenticationScheme> _cachedSchemes; private readonly Dictionary<string, DynamicAuthenticationScheme> _cachedSchemes;
private readonly Dictionary<string, DynamicAuthenticationScheme> _cachedHandlerSchemes; private readonly Dictionary<string, DynamicAuthenticationScheme> _cachedHandlerSchemes;
private readonly SemaphoreSlim _semaphore; private readonly SemaphoreSlim _semaphore;
private readonly IHttpContextAccessor _httpContextAccessor; private readonly IServiceProvider _serviceProvider;
private DateTime? _lastSchemeLoad; private DateTime? _lastSchemeLoad;
private IEnumerable<DynamicAuthenticationScheme> _schemesCopy = Array.Empty<DynamicAuthenticationScheme>(); private IEnumerable<DynamicAuthenticationScheme> _schemesCopy = Array.Empty<DynamicAuthenticationScheme>();
@ -50,7 +50,7 @@ public class DynamicAuthenticationSchemeProvider : AuthenticationSchemeProvider
ILogger<DynamicAuthenticationSchemeProvider> logger, ILogger<DynamicAuthenticationSchemeProvider> logger,
GlobalSettings globalSettings, GlobalSettings globalSettings,
SamlEnvironment samlEnvironment, SamlEnvironment samlEnvironment,
IHttpContextAccessor httpContextAccessor) IServiceProvider serviceProvider)
: base(options) : base(options)
{ {
_oidcPostConfigureOptions = oidcPostConfigureOptions; _oidcPostConfigureOptions = oidcPostConfigureOptions;
@ -77,7 +77,7 @@ public class DynamicAuthenticationSchemeProvider : AuthenticationSchemeProvider
_cachedSchemes = new Dictionary<string, DynamicAuthenticationScheme>(); _cachedSchemes = new Dictionary<string, DynamicAuthenticationScheme>();
_cachedHandlerSchemes = new Dictionary<string, DynamicAuthenticationScheme>(); _cachedHandlerSchemes = new Dictionary<string, DynamicAuthenticationScheme>();
_semaphore = new SemaphoreSlim(1); _semaphore = new SemaphoreSlim(1);
_httpContextAccessor = httpContextAccessor ?? throw new ArgumentNullException(nameof(httpContextAccessor)); _serviceProvider = serviceProvider ?? throw new ArgumentNullException(nameof(serviceProvider));
} }
private bool CacheIsValid private bool CacheIsValid
@ -324,7 +324,7 @@ public class DynamicAuthenticationSchemeProvider : AuthenticationSchemeProvider
oidcOptions.Scope.AddIfNotExists(OpenIdConnectScopes.Acr); oidcOptions.Scope.AddIfNotExists(OpenIdConnectScopes.Acr);
} }
oidcOptions.StateDataFormat = new DistributedCacheStateDataFormatter(_httpContextAccessor, name); oidcOptions.StateDataFormat = new DistributedCacheStateDataFormatter(_serviceProvider, name);
// see: https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest (acr_values) // see: https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest (acr_values)
if (!string.IsNullOrWhiteSpace(config.AcrValues)) if (!string.IsNullOrWhiteSpace(config.AcrValues))

View File

@ -4,8 +4,8 @@ using Bit.Core.Utilities;
using Bit.SharedWeb.Utilities; using Bit.SharedWeb.Utilities;
using Bit.Sso.IdentityServer; using Bit.Sso.IdentityServer;
using Bit.Sso.Models; using Bit.Sso.Models;
using IdentityServer4.Models; using Duende.IdentityServer.Models;
using IdentityServer4.ResponseHandling; using Duende.IdentityServer.ResponseHandling;
using Microsoft.AspNetCore.Authentication.OpenIdConnect; using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Sustainsys.Saml2.AspNetCore2; using Sustainsys.Saml2.AspNetCore2;
@ -59,6 +59,7 @@ public static class ServiceCollectionExtensions
options.UserInteraction.ErrorIdParameter = "errorId"; options.UserInteraction.ErrorIdParameter = "errorId";
} }
options.InputLengthRestrictions.UserName = 256; options.InputLengthRestrictions.UserName = 256;
options.KeyManagement.Enabled = false;
}) })
.AddInMemoryCaching() .AddInMemoryCaching()
.AddInMemoryClients(new List<Client> .AddInMemoryClients(new List<Client>

View File

@ -209,6 +209,24 @@
"Microsoft.Win32.Registry": "5.0.0" "Microsoft.Win32.Registry": "5.0.0"
} }
}, },
"Duende.IdentityServer": {
"type": "Transitive",
"resolved": "6.0.4",
"contentHash": "4HVjzx1F8v5J+U7oa8RGAQGj2QzmzNSu87r18Sh+dlh10uyZZL8teAaT/FaVLDObnfItGdPFvN8mwpF/HkI3Xw==",
"dependencies": {
"Duende.IdentityServer.Storage": "6.0.4",
"Microsoft.AspNetCore.Authentication.OpenIdConnect": "6.0.0"
}
},
"Duende.IdentityServer.Storage": {
"type": "Transitive",
"resolved": "6.0.4",
"contentHash": "s5gAjfbpr2IMgI+fU2Nx+2AZdzstmbt9gpo13iX7GwvqSeSaBVqj9ZskAN0R2KF1OemPdZuGnfaTcevdXMUrrw==",
"dependencies": {
"IdentityModel": "6.0.0",
"Microsoft.AspNetCore.DataProtection.Abstractions": "6.0.0"
}
},
"Fido2": { "Fido2": {
"type": "Transitive", "type": "Transitive",
"resolved": "3.0.1", "resolved": "3.0.1",
@ -245,49 +263,8 @@
}, },
"IdentityModel": { "IdentityModel": {
"type": "Transitive", "type": "Transitive",
"resolved": "4.4.0", "resolved": "6.0.0",
"contentHash": "b18wrIx5wnZlMxAX7oVsE+nDtAJ4hajYlH0xPlaRvo4r/fz08K6pPeZvbiqS9nfNbzfIgLFmNX+FL9qR9ZR5PA==", "contentHash": "eVHCR7a6m/dm5RFcBzE3qs/Jg5j9R5Rjpu8aTOv9e4AFvaQtBXb5ah7kmwU+YwA0ufRwz4wf1hnIvsD2hSnI4g=="
"dependencies": {
"Newtonsoft.Json": "11.0.2",
"System.Text.Encodings.Web": "4.7.0"
}
},
"IdentityModel.AspNetCore.OAuth2Introspection": {
"type": "Transitive",
"resolved": "4.0.1",
"contentHash": "ZNdMZMaj9fqR3j50vYsu+1U3QGd6n8+fqwf+a8mCTcmXGor+HgFDfdq0mM34bsmD6uEgAQup7sv2ZW5kR36dbA==",
"dependencies": {
"IdentityModel": "4.0.0"
}
},
"IdentityServer4": {
"type": "Transitive",
"resolved": "4.1.2",
"contentHash": "blaxxGuOA7v/w1q+fxn97wZ+x2ecG1ZD4mc/N/ZOXMNeFZZhqv+4LF26Gecyik3nWrJPmbMEtQbLmRsKG8k61w==",
"dependencies": {
"IdentityModel": "4.4.0",
"IdentityServer4.Storage": "4.1.2",
"Microsoft.AspNetCore.Authentication.OpenIdConnect": "3.1.0",
"Microsoft.IdentityModel.Protocols.OpenIdConnect": "5.6.0",
"Newtonsoft.Json": "12.0.2"
}
},
"IdentityServer4.AccessTokenValidation": {
"type": "Transitive",
"resolved": "3.0.1",
"contentHash": "qu/M6UyN4o9NVep7q545Ms7hYAnsQqSdLbN1Fjjrn4m35lyBfeQPSSNzDryAKHbodyWOQfHaOqKEyMEJQ5Rpgw==",
"dependencies": {
"IdentityModel.AspNetCore.OAuth2Introspection": "4.0.1",
"Microsoft.AspNetCore.Authentication.JwtBearer": "3.0.0"
}
},
"IdentityServer4.Storage": {
"type": "Transitive",
"resolved": "4.1.2",
"contentHash": "KoSffyZyyeCNTIyJiZnCuPakJ1QbCHlpty6gbWUj/7yl+w0PXIchgmmJnJSvddzBb8iZ2xew/vGlxWUIP17P2g==",
"dependencies": {
"IdentityModel": "4.4.0"
}
}, },
"LaunchDarkly.Cache": { "LaunchDarkly.Cache": {
"type": "Transitive", "type": "Transitive",
@ -421,10 +398,10 @@
}, },
"Microsoft.AspNetCore.Authentication.OpenIdConnect": { "Microsoft.AspNetCore.Authentication.OpenIdConnect": {
"type": "Transitive", "type": "Transitive",
"resolved": "3.1.0", "resolved": "6.0.0",
"contentHash": "O1cAQYUTU8EfRqwc5/rfTns4E4hKlFlg59fuKRrST+PzsxI6H07KqRN/JjdYhAuVYxF8jPnIGbj+zuc5paOWUw==", "contentHash": "cJxdro36spFzk/K2OFCddM6vZ+yoj6ug8mTFRH3Gdv1Pul/buSuCtfb/FSCp31UmS5S4C1315dU7wX3ErLFuDg==",
"dependencies": { "dependencies": {
"Microsoft.IdentityModel.Protocols.OpenIdConnect": "5.5.0" "Microsoft.IdentityModel.Protocols.OpenIdConnect": "6.10.0"
} }
}, },
"Microsoft.AspNetCore.Cryptography.Internal": { "Microsoft.AspNetCore.Cryptography.Internal": {
@ -457,8 +434,8 @@
}, },
"Microsoft.AspNetCore.DataProtection.Abstractions": { "Microsoft.AspNetCore.DataProtection.Abstractions": {
"type": "Transitive", "type": "Transitive",
"resolved": "3.1.32", "resolved": "6.0.0",
"contentHash": "MPL4iVyiaRxnOUY5VATHjvhDWaAEFb77KFiUxVRklv3Z3v+STofUr1UG/aCt1O9cgN7FVTDaC5A7U+zsLub8Xg==" "contentHash": "Z/UU4NEBm5UgNufJmw+j5baW26ytCOIZ0G7sZocPaOzsUeBon1bkM3lSMNZQG2GmDjAIVP2XMSODf2jzSGbibw=="
}, },
"Microsoft.AspNetCore.Http.Abstractions": { "Microsoft.AspNetCore.Http.Abstractions": {
"type": "Transitive", "type": "Transitive",
@ -2777,10 +2754,9 @@
"BitPay.Light": "[1.0.1907, )", "BitPay.Light": "[1.0.1907, )",
"Braintree": "[5.19.0, )", "Braintree": "[5.19.0, )",
"DnsClient": "[1.7.0, )", "DnsClient": "[1.7.0, )",
"Duende.IdentityServer": "[6.0.4, )",
"Fido2.AspNet": "[3.0.1, )", "Fido2.AspNet": "[3.0.1, )",
"Handlebars.Net": "[2.1.2, )", "Handlebars.Net": "[2.1.2, )",
"IdentityServer4": "[4.1.2, )",
"IdentityServer4.AccessTokenValidation": "[3.0.1, )",
"LaunchDarkly.ServerSdk": "[8.0.0, )", "LaunchDarkly.ServerSdk": "[8.0.0, )",
"MailKit": "[4.2.0, )", "MailKit": "[4.2.0, )",
"Microsoft.AspNetCore.Authentication.JwtBearer": "[6.0.4, )", "Microsoft.AspNetCore.Authentication.JwtBearer": "[6.0.4, )",
@ -2808,7 +2784,7 @@
"infrastructure.dapper": { "infrastructure.dapper": {
"type": "Project", "type": "Project",
"dependencies": { "dependencies": {
"Core": "[2023.10.2, )", "Core": "[2023.10.3, )",
"Dapper": "[2.0.123, )" "Dapper": "[2.0.123, )"
} }
}, },
@ -2816,7 +2792,7 @@
"type": "Project", "type": "Project",
"dependencies": { "dependencies": {
"AutoMapper.Extensions.Microsoft.DependencyInjection": "[12.0.1, )", "AutoMapper.Extensions.Microsoft.DependencyInjection": "[12.0.1, )",
"Core": "[2023.10.2, )", "Core": "[2023.10.3, )",
"Microsoft.EntityFrameworkCore.Relational": "[7.0.5, )", "Microsoft.EntityFrameworkCore.Relational": "[7.0.5, )",
"Microsoft.EntityFrameworkCore.SqlServer": "[7.0.5, )", "Microsoft.EntityFrameworkCore.SqlServer": "[7.0.5, )",
"Microsoft.EntityFrameworkCore.Sqlite": "[7.0.5, )", "Microsoft.EntityFrameworkCore.Sqlite": "[7.0.5, )",
@ -2828,9 +2804,9 @@
"sharedweb": { "sharedweb": {
"type": "Project", "type": "Project",
"dependencies": { "dependencies": {
"Core": "[2023.10.2, )", "Core": "[2023.10.3, )",
"Infrastructure.Dapper": "[2023.10.2, )", "Infrastructure.Dapper": "[2023.10.3, )",
"Infrastructure.EntityFramework": "[2023.10.2, )" "Infrastructure.EntityFramework": "[2023.10.3, )"
} }
} }
} }

View File

@ -239,6 +239,24 @@
"Microsoft.Win32.Registry": "5.0.0" "Microsoft.Win32.Registry": "5.0.0"
} }
}, },
"Duende.IdentityServer": {
"type": "Transitive",
"resolved": "6.0.4",
"contentHash": "4HVjzx1F8v5J+U7oa8RGAQGj2QzmzNSu87r18Sh+dlh10uyZZL8teAaT/FaVLDObnfItGdPFvN8mwpF/HkI3Xw==",
"dependencies": {
"Duende.IdentityServer.Storage": "6.0.4",
"Microsoft.AspNetCore.Authentication.OpenIdConnect": "6.0.0"
}
},
"Duende.IdentityServer.Storage": {
"type": "Transitive",
"resolved": "6.0.4",
"contentHash": "s5gAjfbpr2IMgI+fU2Nx+2AZdzstmbt9gpo13iX7GwvqSeSaBVqj9ZskAN0R2KF1OemPdZuGnfaTcevdXMUrrw==",
"dependencies": {
"IdentityModel": "6.0.0",
"Microsoft.AspNetCore.DataProtection.Abstractions": "6.0.0"
}
},
"Fare": { "Fare": {
"type": "Transitive", "type": "Transitive",
"resolved": "2.1.1", "resolved": "2.1.1",
@ -283,49 +301,8 @@
}, },
"IdentityModel": { "IdentityModel": {
"type": "Transitive", "type": "Transitive",
"resolved": "4.4.0", "resolved": "6.0.0",
"contentHash": "b18wrIx5wnZlMxAX7oVsE+nDtAJ4hajYlH0xPlaRvo4r/fz08K6pPeZvbiqS9nfNbzfIgLFmNX+FL9qR9ZR5PA==", "contentHash": "eVHCR7a6m/dm5RFcBzE3qs/Jg5j9R5Rjpu8aTOv9e4AFvaQtBXb5ah7kmwU+YwA0ufRwz4wf1hnIvsD2hSnI4g=="
"dependencies": {
"Newtonsoft.Json": "11.0.2",
"System.Text.Encodings.Web": "4.7.0"
}
},
"IdentityModel.AspNetCore.OAuth2Introspection": {
"type": "Transitive",
"resolved": "4.0.1",
"contentHash": "ZNdMZMaj9fqR3j50vYsu+1U3QGd6n8+fqwf+a8mCTcmXGor+HgFDfdq0mM34bsmD6uEgAQup7sv2ZW5kR36dbA==",
"dependencies": {
"IdentityModel": "4.0.0"
}
},
"IdentityServer4": {
"type": "Transitive",
"resolved": "4.1.2",
"contentHash": "blaxxGuOA7v/w1q+fxn97wZ+x2ecG1ZD4mc/N/ZOXMNeFZZhqv+4LF26Gecyik3nWrJPmbMEtQbLmRsKG8k61w==",
"dependencies": {
"IdentityModel": "4.4.0",
"IdentityServer4.Storage": "4.1.2",
"Microsoft.AspNetCore.Authentication.OpenIdConnect": "3.1.0",
"Microsoft.IdentityModel.Protocols.OpenIdConnect": "5.6.0",
"Newtonsoft.Json": "12.0.2"
}
},
"IdentityServer4.AccessTokenValidation": {
"type": "Transitive",
"resolved": "3.0.1",
"contentHash": "qu/M6UyN4o9NVep7q545Ms7hYAnsQqSdLbN1Fjjrn4m35lyBfeQPSSNzDryAKHbodyWOQfHaOqKEyMEJQ5Rpgw==",
"dependencies": {
"IdentityModel.AspNetCore.OAuth2Introspection": "4.0.1",
"Microsoft.AspNetCore.Authentication.JwtBearer": "3.0.0"
}
},
"IdentityServer4.Storage": {
"type": "Transitive",
"resolved": "4.1.2",
"contentHash": "KoSffyZyyeCNTIyJiZnCuPakJ1QbCHlpty6gbWUj/7yl+w0PXIchgmmJnJSvddzBb8iZ2xew/vGlxWUIP17P2g==",
"dependencies": {
"IdentityModel": "4.4.0"
}
}, },
"Kralizek.AutoFixture.Extensions.MockHttp": { "Kralizek.AutoFixture.Extensions.MockHttp": {
"type": "Transitive", "type": "Transitive",
@ -412,10 +389,10 @@
}, },
"Microsoft.AspNetCore.Authentication.OpenIdConnect": { "Microsoft.AspNetCore.Authentication.OpenIdConnect": {
"type": "Transitive", "type": "Transitive",
"resolved": "3.1.0", "resolved": "6.0.0",
"contentHash": "O1cAQYUTU8EfRqwc5/rfTns4E4hKlFlg59fuKRrST+PzsxI6H07KqRN/JjdYhAuVYxF8jPnIGbj+zuc5paOWUw==", "contentHash": "cJxdro36spFzk/K2OFCddM6vZ+yoj6ug8mTFRH3Gdv1Pul/buSuCtfb/FSCp31UmS5S4C1315dU7wX3ErLFuDg==",
"dependencies": { "dependencies": {
"Microsoft.IdentityModel.Protocols.OpenIdConnect": "5.5.0" "Microsoft.IdentityModel.Protocols.OpenIdConnect": "6.10.0"
} }
}, },
"Microsoft.AspNetCore.Cryptography.Internal": { "Microsoft.AspNetCore.Cryptography.Internal": {
@ -448,8 +425,8 @@
}, },
"Microsoft.AspNetCore.DataProtection.Abstractions": { "Microsoft.AspNetCore.DataProtection.Abstractions": {
"type": "Transitive", "type": "Transitive",
"resolved": "3.1.32", "resolved": "6.0.0",
"contentHash": "MPL4iVyiaRxnOUY5VATHjvhDWaAEFb77KFiUxVRklv3Z3v+STofUr1UG/aCt1O9cgN7FVTDaC5A7U+zsLub8Xg==" "contentHash": "Z/UU4NEBm5UgNufJmw+j5baW26ytCOIZ0G7sZocPaOzsUeBon1bkM3lSMNZQG2GmDjAIVP2XMSODf2jzSGbibw=="
}, },
"Microsoft.Azure.Amqp": { "Microsoft.Azure.Amqp": {
"type": "Transitive", "type": "Transitive",
@ -2680,7 +2657,7 @@
"commercial.core": { "commercial.core": {
"type": "Project", "type": "Project",
"dependencies": { "dependencies": {
"Core": "[2023.10.2, )" "Core": "[2023.10.3, )"
} }
}, },
"common": { "common": {
@ -2688,7 +2665,7 @@
"dependencies": { "dependencies": {
"AutoFixture.AutoNSubstitute": "[4.17.0, )", "AutoFixture.AutoNSubstitute": "[4.17.0, )",
"AutoFixture.Xunit2": "[4.17.0, )", "AutoFixture.Xunit2": "[4.17.0, )",
"Core": "[2023.10.2, )", "Core": "[2023.10.3, )",
"Kralizek.AutoFixture.Extensions.MockHttp": "[1.2.0, )", "Kralizek.AutoFixture.Extensions.MockHttp": "[1.2.0, )",
"Microsoft.NET.Test.Sdk": "[17.1.0, )", "Microsoft.NET.Test.Sdk": "[17.1.0, )",
"NSubstitute": "[4.3.0, )", "NSubstitute": "[4.3.0, )",
@ -2710,10 +2687,9 @@
"BitPay.Light": "[1.0.1907, )", "BitPay.Light": "[1.0.1907, )",
"Braintree": "[5.19.0, )", "Braintree": "[5.19.0, )",
"DnsClient": "[1.7.0, )", "DnsClient": "[1.7.0, )",
"Duende.IdentityServer": "[6.0.4, )",
"Fido2.AspNet": "[3.0.1, )", "Fido2.AspNet": "[3.0.1, )",
"Handlebars.Net": "[2.1.2, )", "Handlebars.Net": "[2.1.2, )",
"IdentityServer4": "[4.1.2, )",
"IdentityServer4.AccessTokenValidation": "[3.0.1, )",
"LaunchDarkly.ServerSdk": "[8.0.0, )", "LaunchDarkly.ServerSdk": "[8.0.0, )",
"MailKit": "[4.2.0, )", "MailKit": "[4.2.0, )",
"Microsoft.AspNetCore.Authentication.JwtBearer": "[6.0.4, )", "Microsoft.AspNetCore.Authentication.JwtBearer": "[6.0.4, )",
@ -2743,8 +2719,8 @@
"dependencies": { "dependencies": {
"AutoFixture.AutoNSubstitute": "[4.17.0, )", "AutoFixture.AutoNSubstitute": "[4.17.0, )",
"AutoFixture.Xunit2": "[4.17.0, )", "AutoFixture.Xunit2": "[4.17.0, )",
"Common": "[2023.10.2, )", "Common": "[2023.10.3, )",
"Core": "[2023.10.2, )", "Core": "[2023.10.3, )",
"Kralizek.AutoFixture.Extensions.MockHttp": "[1.2.0, )", "Kralizek.AutoFixture.Extensions.MockHttp": "[1.2.0, )",
"Microsoft.NET.Test.Sdk": "[17.1.0, )", "Microsoft.NET.Test.Sdk": "[17.1.0, )",
"NSubstitute": "[4.3.0, )", "NSubstitute": "[4.3.0, )",

View File

@ -282,6 +282,24 @@
"Microsoft.Win32.Registry": "5.0.0" "Microsoft.Win32.Registry": "5.0.0"
} }
}, },
"Duende.IdentityServer": {
"type": "Transitive",
"resolved": "6.0.4",
"contentHash": "4HVjzx1F8v5J+U7oa8RGAQGj2QzmzNSu87r18Sh+dlh10uyZZL8teAaT/FaVLDObnfItGdPFvN8mwpF/HkI3Xw==",
"dependencies": {
"Duende.IdentityServer.Storage": "6.0.4",
"Microsoft.AspNetCore.Authentication.OpenIdConnect": "6.0.0"
}
},
"Duende.IdentityServer.Storage": {
"type": "Transitive",
"resolved": "6.0.4",
"contentHash": "s5gAjfbpr2IMgI+fU2Nx+2AZdzstmbt9gpo13iX7GwvqSeSaBVqj9ZskAN0R2KF1OemPdZuGnfaTcevdXMUrrw==",
"dependencies": {
"IdentityModel": "6.0.0",
"Microsoft.AspNetCore.DataProtection.Abstractions": "6.0.0"
}
},
"Fare": { "Fare": {
"type": "Transitive", "type": "Transitive",
"resolved": "2.1.1", "resolved": "2.1.1",
@ -326,49 +344,8 @@
}, },
"IdentityModel": { "IdentityModel": {
"type": "Transitive", "type": "Transitive",
"resolved": "4.4.0", "resolved": "6.0.0",
"contentHash": "b18wrIx5wnZlMxAX7oVsE+nDtAJ4hajYlH0xPlaRvo4r/fz08K6pPeZvbiqS9nfNbzfIgLFmNX+FL9qR9ZR5PA==", "contentHash": "eVHCR7a6m/dm5RFcBzE3qs/Jg5j9R5Rjpu8aTOv9e4AFvaQtBXb5ah7kmwU+YwA0ufRwz4wf1hnIvsD2hSnI4g=="
"dependencies": {
"Newtonsoft.Json": "11.0.2",
"System.Text.Encodings.Web": "4.7.0"
}
},
"IdentityModel.AspNetCore.OAuth2Introspection": {
"type": "Transitive",
"resolved": "4.0.1",
"contentHash": "ZNdMZMaj9fqR3j50vYsu+1U3QGd6n8+fqwf+a8mCTcmXGor+HgFDfdq0mM34bsmD6uEgAQup7sv2ZW5kR36dbA==",
"dependencies": {
"IdentityModel": "4.0.0"
}
},
"IdentityServer4": {
"type": "Transitive",
"resolved": "4.1.2",
"contentHash": "blaxxGuOA7v/w1q+fxn97wZ+x2ecG1ZD4mc/N/ZOXMNeFZZhqv+4LF26Gecyik3nWrJPmbMEtQbLmRsKG8k61w==",
"dependencies": {
"IdentityModel": "4.4.0",
"IdentityServer4.Storage": "4.1.2",
"Microsoft.AspNetCore.Authentication.OpenIdConnect": "3.1.0",
"Microsoft.IdentityModel.Protocols.OpenIdConnect": "5.6.0",
"Newtonsoft.Json": "12.0.2"
}
},
"IdentityServer4.AccessTokenValidation": {
"type": "Transitive",
"resolved": "3.0.1",
"contentHash": "qu/M6UyN4o9NVep7q545Ms7hYAnsQqSdLbN1Fjjrn4m35lyBfeQPSSNzDryAKHbodyWOQfHaOqKEyMEJQ5Rpgw==",
"dependencies": {
"IdentityModel.AspNetCore.OAuth2Introspection": "4.0.1",
"Microsoft.AspNetCore.Authentication.JwtBearer": "3.0.0"
}
},
"IdentityServer4.Storage": {
"type": "Transitive",
"resolved": "4.1.2",
"contentHash": "KoSffyZyyeCNTIyJiZnCuPakJ1QbCHlpty6gbWUj/7yl+w0PXIchgmmJnJSvddzBb8iZ2xew/vGlxWUIP17P2g==",
"dependencies": {
"IdentityModel": "4.4.0"
}
}, },
"Kralizek.AutoFixture.Extensions.MockHttp": { "Kralizek.AutoFixture.Extensions.MockHttp": {
"type": "Transitive", "type": "Transitive",
@ -469,10 +446,10 @@
}, },
"Microsoft.AspNetCore.Authentication.OpenIdConnect": { "Microsoft.AspNetCore.Authentication.OpenIdConnect": {
"type": "Transitive", "type": "Transitive",
"resolved": "3.1.0", "resolved": "6.0.0",
"contentHash": "O1cAQYUTU8EfRqwc5/rfTns4E4hKlFlg59fuKRrST+PzsxI6H07KqRN/JjdYhAuVYxF8jPnIGbj+zuc5paOWUw==", "contentHash": "cJxdro36spFzk/K2OFCddM6vZ+yoj6ug8mTFRH3Gdv1Pul/buSuCtfb/FSCp31UmS5S4C1315dU7wX3ErLFuDg==",
"dependencies": { "dependencies": {
"Microsoft.IdentityModel.Protocols.OpenIdConnect": "5.5.0" "Microsoft.IdentityModel.Protocols.OpenIdConnect": "6.10.0"
} }
}, },
"Microsoft.AspNetCore.Cryptography.Internal": { "Microsoft.AspNetCore.Cryptography.Internal": {
@ -505,8 +482,8 @@
}, },
"Microsoft.AspNetCore.DataProtection.Abstractions": { "Microsoft.AspNetCore.DataProtection.Abstractions": {
"type": "Transitive", "type": "Transitive",
"resolved": "3.1.32", "resolved": "6.0.0",
"contentHash": "MPL4iVyiaRxnOUY5VATHjvhDWaAEFb77KFiUxVRklv3Z3v+STofUr1UG/aCt1O9cgN7FVTDaC5A7U+zsLub8Xg==" "contentHash": "Z/UU4NEBm5UgNufJmw+j5baW26ytCOIZ0G7sZocPaOzsUeBon1bkM3lSMNZQG2GmDjAIVP2XMSODf2jzSGbibw=="
}, },
"Microsoft.AspNetCore.TestHost": { "Microsoft.AspNetCore.TestHost": {
"type": "Transitive", "type": "Transitive",
@ -2997,7 +2974,7 @@
"dependencies": { "dependencies": {
"AutoFixture.AutoNSubstitute": "[4.17.0, )", "AutoFixture.AutoNSubstitute": "[4.17.0, )",
"AutoFixture.Xunit2": "[4.17.0, )", "AutoFixture.Xunit2": "[4.17.0, )",
"Core": "[2023.10.2, )", "Core": "[2023.10.3, )",
"Kralizek.AutoFixture.Extensions.MockHttp": "[1.2.0, )", "Kralizek.AutoFixture.Extensions.MockHttp": "[1.2.0, )",
"Microsoft.NET.Test.Sdk": "[17.1.0, )", "Microsoft.NET.Test.Sdk": "[17.1.0, )",
"NSubstitute": "[4.3.0, )", "NSubstitute": "[4.3.0, )",
@ -3019,10 +2996,9 @@
"BitPay.Light": "[1.0.1907, )", "BitPay.Light": "[1.0.1907, )",
"Braintree": "[5.19.0, )", "Braintree": "[5.19.0, )",
"DnsClient": "[1.7.0, )", "DnsClient": "[1.7.0, )",
"Duende.IdentityServer": "[6.0.4, )",
"Fido2.AspNet": "[3.0.1, )", "Fido2.AspNet": "[3.0.1, )",
"Handlebars.Net": "[2.1.2, )", "Handlebars.Net": "[2.1.2, )",
"IdentityServer4": "[4.1.2, )",
"IdentityServer4.AccessTokenValidation": "[3.0.1, )",
"LaunchDarkly.ServerSdk": "[8.0.0, )", "LaunchDarkly.ServerSdk": "[8.0.0, )",
"MailKit": "[4.2.0, )", "MailKit": "[4.2.0, )",
"Microsoft.AspNetCore.Authentication.JwtBearer": "[6.0.4, )", "Microsoft.AspNetCore.Authentication.JwtBearer": "[6.0.4, )",
@ -3050,15 +3026,15 @@
"identity": { "identity": {
"type": "Project", "type": "Project",
"dependencies": { "dependencies": {
"Core": "[2023.10.2, )", "Core": "[2023.10.3, )",
"SharedWeb": "[2023.10.2, )", "SharedWeb": "[2023.10.3, )",
"Swashbuckle.AspNetCore.SwaggerGen": "[6.5.0, )" "Swashbuckle.AspNetCore.SwaggerGen": "[6.5.0, )"
} }
}, },
"infrastructure.dapper": { "infrastructure.dapper": {
"type": "Project", "type": "Project",
"dependencies": { "dependencies": {
"Core": "[2023.10.2, )", "Core": "[2023.10.3, )",
"Dapper": "[2.0.123, )" "Dapper": "[2.0.123, )"
} }
}, },
@ -3066,7 +3042,7 @@
"type": "Project", "type": "Project",
"dependencies": { "dependencies": {
"AutoMapper.Extensions.Microsoft.DependencyInjection": "[12.0.1, )", "AutoMapper.Extensions.Microsoft.DependencyInjection": "[12.0.1, )",
"Core": "[2023.10.2, )", "Core": "[2023.10.3, )",
"Microsoft.EntityFrameworkCore.Relational": "[7.0.5, )", "Microsoft.EntityFrameworkCore.Relational": "[7.0.5, )",
"Microsoft.EntityFrameworkCore.SqlServer": "[7.0.5, )", "Microsoft.EntityFrameworkCore.SqlServer": "[7.0.5, )",
"Microsoft.EntityFrameworkCore.Sqlite": "[7.0.5, )", "Microsoft.EntityFrameworkCore.Sqlite": "[7.0.5, )",
@ -3078,8 +3054,8 @@
"integrationtestcommon": { "integrationtestcommon": {
"type": "Project", "type": "Project",
"dependencies": { "dependencies": {
"Common": "[2023.10.2, )", "Common": "[2023.10.3, )",
"Identity": "[2023.10.2, )", "Identity": "[2023.10.3, )",
"Microsoft.AspNetCore.Mvc.Testing": "[6.0.5, )", "Microsoft.AspNetCore.Mvc.Testing": "[6.0.5, )",
"Microsoft.Extensions.Configuration": "[6.0.1, )" "Microsoft.Extensions.Configuration": "[6.0.1, )"
} }
@ -3087,16 +3063,16 @@
"scim": { "scim": {
"type": "Project", "type": "Project",
"dependencies": { "dependencies": {
"Core": "[2023.10.2, )", "Core": "[2023.10.3, )",
"SharedWeb": "[2023.10.2, )" "SharedWeb": "[2023.10.3, )"
} }
}, },
"sharedweb": { "sharedweb": {
"type": "Project", "type": "Project",
"dependencies": { "dependencies": {
"Core": "[2023.10.2, )", "Core": "[2023.10.3, )",
"Infrastructure.Dapper": "[2023.10.2, )", "Infrastructure.Dapper": "[2023.10.3, )",
"Infrastructure.EntityFramework": "[2023.10.2, )" "Infrastructure.EntityFramework": "[2023.10.3, )"
} }
} }
} }

View File

@ -270,6 +270,24 @@
"Microsoft.Win32.Registry": "5.0.0" "Microsoft.Win32.Registry": "5.0.0"
} }
}, },
"Duende.IdentityServer": {
"type": "Transitive",
"resolved": "6.0.4",
"contentHash": "4HVjzx1F8v5J+U7oa8RGAQGj2QzmzNSu87r18Sh+dlh10uyZZL8teAaT/FaVLDObnfItGdPFvN8mwpF/HkI3Xw==",
"dependencies": {
"Duende.IdentityServer.Storage": "6.0.4",
"Microsoft.AspNetCore.Authentication.OpenIdConnect": "6.0.0"
}
},
"Duende.IdentityServer.Storage": {
"type": "Transitive",
"resolved": "6.0.4",
"contentHash": "s5gAjfbpr2IMgI+fU2Nx+2AZdzstmbt9gpo13iX7GwvqSeSaBVqj9ZskAN0R2KF1OemPdZuGnfaTcevdXMUrrw==",
"dependencies": {
"IdentityModel": "6.0.0",
"Microsoft.AspNetCore.DataProtection.Abstractions": "6.0.0"
}
},
"Fare": { "Fare": {
"type": "Transitive", "type": "Transitive",
"resolved": "2.1.1", "resolved": "2.1.1",
@ -314,49 +332,8 @@
}, },
"IdentityModel": { "IdentityModel": {
"type": "Transitive", "type": "Transitive",
"resolved": "4.4.0", "resolved": "6.0.0",
"contentHash": "b18wrIx5wnZlMxAX7oVsE+nDtAJ4hajYlH0xPlaRvo4r/fz08K6pPeZvbiqS9nfNbzfIgLFmNX+FL9qR9ZR5PA==", "contentHash": "eVHCR7a6m/dm5RFcBzE3qs/Jg5j9R5Rjpu8aTOv9e4AFvaQtBXb5ah7kmwU+YwA0ufRwz4wf1hnIvsD2hSnI4g=="
"dependencies": {
"Newtonsoft.Json": "11.0.2",
"System.Text.Encodings.Web": "4.7.0"
}
},
"IdentityModel.AspNetCore.OAuth2Introspection": {
"type": "Transitive",
"resolved": "4.0.1",
"contentHash": "ZNdMZMaj9fqR3j50vYsu+1U3QGd6n8+fqwf+a8mCTcmXGor+HgFDfdq0mM34bsmD6uEgAQup7sv2ZW5kR36dbA==",
"dependencies": {
"IdentityModel": "4.0.0"
}
},
"IdentityServer4": {
"type": "Transitive",
"resolved": "4.1.2",
"contentHash": "blaxxGuOA7v/w1q+fxn97wZ+x2ecG1ZD4mc/N/ZOXMNeFZZhqv+4LF26Gecyik3nWrJPmbMEtQbLmRsKG8k61w==",
"dependencies": {
"IdentityModel": "4.4.0",
"IdentityServer4.Storage": "4.1.2",
"Microsoft.AspNetCore.Authentication.OpenIdConnect": "3.1.0",
"Microsoft.IdentityModel.Protocols.OpenIdConnect": "5.6.0",
"Newtonsoft.Json": "12.0.2"
}
},
"IdentityServer4.AccessTokenValidation": {
"type": "Transitive",
"resolved": "3.0.1",
"contentHash": "qu/M6UyN4o9NVep7q545Ms7hYAnsQqSdLbN1Fjjrn4m35lyBfeQPSSNzDryAKHbodyWOQfHaOqKEyMEJQ5Rpgw==",
"dependencies": {
"IdentityModel.AspNetCore.OAuth2Introspection": "4.0.1",
"Microsoft.AspNetCore.Authentication.JwtBearer": "3.0.0"
}
},
"IdentityServer4.Storage": {
"type": "Transitive",
"resolved": "4.1.2",
"contentHash": "KoSffyZyyeCNTIyJiZnCuPakJ1QbCHlpty6gbWUj/7yl+w0PXIchgmmJnJSvddzBb8iZ2xew/vGlxWUIP17P2g==",
"dependencies": {
"IdentityModel": "4.4.0"
}
}, },
"Kralizek.AutoFixture.Extensions.MockHttp": { "Kralizek.AutoFixture.Extensions.MockHttp": {
"type": "Transitive", "type": "Transitive",
@ -457,10 +434,10 @@
}, },
"Microsoft.AspNetCore.Authentication.OpenIdConnect": { "Microsoft.AspNetCore.Authentication.OpenIdConnect": {
"type": "Transitive", "type": "Transitive",
"resolved": "3.1.0", "resolved": "6.0.0",
"contentHash": "O1cAQYUTU8EfRqwc5/rfTns4E4hKlFlg59fuKRrST+PzsxI6H07KqRN/JjdYhAuVYxF8jPnIGbj+zuc5paOWUw==", "contentHash": "cJxdro36spFzk/K2OFCddM6vZ+yoj6ug8mTFRH3Gdv1Pul/buSuCtfb/FSCp31UmS5S4C1315dU7wX3ErLFuDg==",
"dependencies": { "dependencies": {
"Microsoft.IdentityModel.Protocols.OpenIdConnect": "5.5.0" "Microsoft.IdentityModel.Protocols.OpenIdConnect": "6.10.0"
} }
}, },
"Microsoft.AspNetCore.Cryptography.Internal": { "Microsoft.AspNetCore.Cryptography.Internal": {
@ -493,8 +470,8 @@
}, },
"Microsoft.AspNetCore.DataProtection.Abstractions": { "Microsoft.AspNetCore.DataProtection.Abstractions": {
"type": "Transitive", "type": "Transitive",
"resolved": "3.1.32", "resolved": "6.0.0",
"contentHash": "MPL4iVyiaRxnOUY5VATHjvhDWaAEFb77KFiUxVRklv3Z3v+STofUr1UG/aCt1O9cgN7FVTDaC5A7U+zsLub8Xg==" "contentHash": "Z/UU4NEBm5UgNufJmw+j5baW26ytCOIZ0G7sZocPaOzsUeBon1bkM3lSMNZQG2GmDjAIVP2XMSODf2jzSGbibw=="
}, },
"Microsoft.Azure.Amqp": { "Microsoft.Azure.Amqp": {
"type": "Transitive", "type": "Transitive",
@ -2850,7 +2827,7 @@
"dependencies": { "dependencies": {
"AutoFixture.AutoNSubstitute": "[4.17.0, )", "AutoFixture.AutoNSubstitute": "[4.17.0, )",
"AutoFixture.Xunit2": "[4.17.0, )", "AutoFixture.Xunit2": "[4.17.0, )",
"Core": "[2023.10.2, )", "Core": "[2023.10.3, )",
"Kralizek.AutoFixture.Extensions.MockHttp": "[1.2.0, )", "Kralizek.AutoFixture.Extensions.MockHttp": "[1.2.0, )",
"Microsoft.NET.Test.Sdk": "[17.1.0, )", "Microsoft.NET.Test.Sdk": "[17.1.0, )",
"NSubstitute": "[4.3.0, )", "NSubstitute": "[4.3.0, )",
@ -2872,10 +2849,9 @@
"BitPay.Light": "[1.0.1907, )", "BitPay.Light": "[1.0.1907, )",
"Braintree": "[5.19.0, )", "Braintree": "[5.19.0, )",
"DnsClient": "[1.7.0, )", "DnsClient": "[1.7.0, )",
"Duende.IdentityServer": "[6.0.4, )",
"Fido2.AspNet": "[3.0.1, )", "Fido2.AspNet": "[3.0.1, )",
"Handlebars.Net": "[2.1.2, )", "Handlebars.Net": "[2.1.2, )",
"IdentityServer4": "[4.1.2, )",
"IdentityServer4.AccessTokenValidation": "[3.0.1, )",
"LaunchDarkly.ServerSdk": "[8.0.0, )", "LaunchDarkly.ServerSdk": "[8.0.0, )",
"MailKit": "[4.2.0, )", "MailKit": "[4.2.0, )",
"Microsoft.AspNetCore.Authentication.JwtBearer": "[6.0.4, )", "Microsoft.AspNetCore.Authentication.JwtBearer": "[6.0.4, )",
@ -2903,7 +2879,7 @@
"infrastructure.dapper": { "infrastructure.dapper": {
"type": "Project", "type": "Project",
"dependencies": { "dependencies": {
"Core": "[2023.10.2, )", "Core": "[2023.10.3, )",
"Dapper": "[2.0.123, )" "Dapper": "[2.0.123, )"
} }
}, },
@ -2911,7 +2887,7 @@
"type": "Project", "type": "Project",
"dependencies": { "dependencies": {
"AutoMapper.Extensions.Microsoft.DependencyInjection": "[12.0.1, )", "AutoMapper.Extensions.Microsoft.DependencyInjection": "[12.0.1, )",
"Core": "[2023.10.2, )", "Core": "[2023.10.3, )",
"Microsoft.EntityFrameworkCore.Relational": "[7.0.5, )", "Microsoft.EntityFrameworkCore.Relational": "[7.0.5, )",
"Microsoft.EntityFrameworkCore.SqlServer": "[7.0.5, )", "Microsoft.EntityFrameworkCore.SqlServer": "[7.0.5, )",
"Microsoft.EntityFrameworkCore.Sqlite": "[7.0.5, )", "Microsoft.EntityFrameworkCore.Sqlite": "[7.0.5, )",
@ -2923,16 +2899,16 @@
"scim": { "scim": {
"type": "Project", "type": "Project",
"dependencies": { "dependencies": {
"Core": "[2023.10.2, )", "Core": "[2023.10.3, )",
"SharedWeb": "[2023.10.2, )" "SharedWeb": "[2023.10.3, )"
} }
}, },
"sharedweb": { "sharedweb": {
"type": "Project", "type": "Project",
"dependencies": { "dependencies": {
"Core": "[2023.10.2, )", "Core": "[2023.10.3, )",
"Infrastructure.Dapper": "[2023.10.2, )", "Infrastructure.Dapper": "[2023.10.3, )",
"Infrastructure.EntityFramework": "[2023.10.2, )" "Infrastructure.EntityFramework": "[2023.10.3, )"
} }
} }
} }

View File

@ -192,6 +192,24 @@
"Microsoft.Win32.Registry": "5.0.0" "Microsoft.Win32.Registry": "5.0.0"
} }
}, },
"Duende.IdentityServer": {
"type": "Transitive",
"resolved": "6.0.4",
"contentHash": "4HVjzx1F8v5J+U7oa8RGAQGj2QzmzNSu87r18Sh+dlh10uyZZL8teAaT/FaVLDObnfItGdPFvN8mwpF/HkI3Xw==",
"dependencies": {
"Duende.IdentityServer.Storage": "6.0.4",
"Microsoft.AspNetCore.Authentication.OpenIdConnect": "6.0.0"
}
},
"Duende.IdentityServer.Storage": {
"type": "Transitive",
"resolved": "6.0.4",
"contentHash": "s5gAjfbpr2IMgI+fU2Nx+2AZdzstmbt9gpo13iX7GwvqSeSaBVqj9ZskAN0R2KF1OemPdZuGnfaTcevdXMUrrw==",
"dependencies": {
"IdentityModel": "6.0.0",
"Microsoft.AspNetCore.DataProtection.Abstractions": "6.0.0"
}
},
"Fido2": { "Fido2": {
"type": "Transitive", "type": "Transitive",
"resolved": "3.0.1", "resolved": "3.0.1",
@ -233,49 +251,8 @@
}, },
"IdentityModel": { "IdentityModel": {
"type": "Transitive", "type": "Transitive",
"resolved": "4.4.0", "resolved": "6.0.0",
"contentHash": "b18wrIx5wnZlMxAX7oVsE+nDtAJ4hajYlH0xPlaRvo4r/fz08K6pPeZvbiqS9nfNbzfIgLFmNX+FL9qR9ZR5PA==", "contentHash": "eVHCR7a6m/dm5RFcBzE3qs/Jg5j9R5Rjpu8aTOv9e4AFvaQtBXb5ah7kmwU+YwA0ufRwz4wf1hnIvsD2hSnI4g=="
"dependencies": {
"Newtonsoft.Json": "11.0.2",
"System.Text.Encodings.Web": "4.7.0"
}
},
"IdentityModel.AspNetCore.OAuth2Introspection": {
"type": "Transitive",
"resolved": "4.0.1",
"contentHash": "ZNdMZMaj9fqR3j50vYsu+1U3QGd6n8+fqwf+a8mCTcmXGor+HgFDfdq0mM34bsmD6uEgAQup7sv2ZW5kR36dbA==",
"dependencies": {
"IdentityModel": "4.0.0"
}
},
"IdentityServer4": {
"type": "Transitive",
"resolved": "4.1.2",
"contentHash": "blaxxGuOA7v/w1q+fxn97wZ+x2ecG1ZD4mc/N/ZOXMNeFZZhqv+4LF26Gecyik3nWrJPmbMEtQbLmRsKG8k61w==",
"dependencies": {
"IdentityModel": "4.4.0",
"IdentityServer4.Storage": "4.1.2",
"Microsoft.AspNetCore.Authentication.OpenIdConnect": "3.1.0",
"Microsoft.IdentityModel.Protocols.OpenIdConnect": "5.6.0",
"Newtonsoft.Json": "12.0.2"
}
},
"IdentityServer4.AccessTokenValidation": {
"type": "Transitive",
"resolved": "3.0.1",
"contentHash": "qu/M6UyN4o9NVep7q545Ms7hYAnsQqSdLbN1Fjjrn4m35lyBfeQPSSNzDryAKHbodyWOQfHaOqKEyMEJQ5Rpgw==",
"dependencies": {
"IdentityModel.AspNetCore.OAuth2Introspection": "4.0.1",
"Microsoft.AspNetCore.Authentication.JwtBearer": "3.0.0"
}
},
"IdentityServer4.Storage": {
"type": "Transitive",
"resolved": "4.1.2",
"contentHash": "KoSffyZyyeCNTIyJiZnCuPakJ1QbCHlpty6gbWUj/7yl+w0PXIchgmmJnJSvddzBb8iZ2xew/vGlxWUIP17P2g==",
"dependencies": {
"IdentityModel": "4.4.0"
}
}, },
"LaunchDarkly.Cache": { "LaunchDarkly.Cache": {
"type": "Transitive", "type": "Transitive",
@ -353,10 +330,10 @@
}, },
"Microsoft.AspNetCore.Authentication.OpenIdConnect": { "Microsoft.AspNetCore.Authentication.OpenIdConnect": {
"type": "Transitive", "type": "Transitive",
"resolved": "3.1.0", "resolved": "6.0.0",
"contentHash": "O1cAQYUTU8EfRqwc5/rfTns4E4hKlFlg59fuKRrST+PzsxI6H07KqRN/JjdYhAuVYxF8jPnIGbj+zuc5paOWUw==", "contentHash": "cJxdro36spFzk/K2OFCddM6vZ+yoj6ug8mTFRH3Gdv1Pul/buSuCtfb/FSCp31UmS5S4C1315dU7wX3ErLFuDg==",
"dependencies": { "dependencies": {
"Microsoft.IdentityModel.Protocols.OpenIdConnect": "5.5.0" "Microsoft.IdentityModel.Protocols.OpenIdConnect": "6.10.0"
} }
}, },
"Microsoft.AspNetCore.Cryptography.Internal": { "Microsoft.AspNetCore.Cryptography.Internal": {
@ -389,8 +366,8 @@
}, },
"Microsoft.AspNetCore.DataProtection.Abstractions": { "Microsoft.AspNetCore.DataProtection.Abstractions": {
"type": "Transitive", "type": "Transitive",
"resolved": "3.1.32", "resolved": "6.0.0",
"contentHash": "MPL4iVyiaRxnOUY5VATHjvhDWaAEFb77KFiUxVRklv3Z3v+STofUr1UG/aCt1O9cgN7FVTDaC5A7U+zsLub8Xg==" "contentHash": "Z/UU4NEBm5UgNufJmw+j5baW26ytCOIZ0G7sZocPaOzsUeBon1bkM3lSMNZQG2GmDjAIVP2XMSODf2jzSGbibw=="
}, },
"Microsoft.Azure.Amqp": { "Microsoft.Azure.Amqp": {
"type": "Transitive", "type": "Transitive",
@ -2557,10 +2534,9 @@
"BitPay.Light": "[1.0.1907, )", "BitPay.Light": "[1.0.1907, )",
"Braintree": "[5.19.0, )", "Braintree": "[5.19.0, )",
"DnsClient": "[1.7.0, )", "DnsClient": "[1.7.0, )",
"Duende.IdentityServer": "[6.0.4, )",
"Fido2.AspNet": "[3.0.1, )", "Fido2.AspNet": "[3.0.1, )",
"Handlebars.Net": "[2.1.2, )", "Handlebars.Net": "[2.1.2, )",
"IdentityServer4": "[4.1.2, )",
"IdentityServer4.AccessTokenValidation": "[3.0.1, )",
"LaunchDarkly.ServerSdk": "[8.0.0, )", "LaunchDarkly.ServerSdk": "[8.0.0, )",
"MailKit": "[4.2.0, )", "MailKit": "[4.2.0, )",
"Microsoft.AspNetCore.Authentication.JwtBearer": "[6.0.4, )", "Microsoft.AspNetCore.Authentication.JwtBearer": "[6.0.4, )",

View File

@ -82,7 +82,11 @@
<label asp-for="PlanType"></label> <label asp-for="PlanType"></label>
@{ @{
var planTypes = Enum.GetValues<PlanType>() var planTypes = Enum.GetValues<PlanType>()
.Where(p => Model.Provider == null || p is >= PlanType.TeamsMonthly and <= PlanType.TeamsStarter) .Where(p =>
Model.Provider == null ||
(Model.Provider != null
&& p is >= PlanType.TeamsMonthly2019 and <= PlanType.EnterpriseAnnually2019 or >= PlanType.TeamsMonthly2020 and <= PlanType.EnterpriseAnnually)
)
.Select(e => new SelectListItem .Select(e => new SelectListItem
{ {
Value = ((int)e).ToString(), Value = ((int)e).ToString(),

View File

@ -223,6 +223,24 @@
"Microsoft.Win32.Registry": "5.0.0" "Microsoft.Win32.Registry": "5.0.0"
} }
}, },
"Duende.IdentityServer": {
"type": "Transitive",
"resolved": "6.0.4",
"contentHash": "4HVjzx1F8v5J+U7oa8RGAQGj2QzmzNSu87r18Sh+dlh10uyZZL8teAaT/FaVLDObnfItGdPFvN8mwpF/HkI3Xw==",
"dependencies": {
"Duende.IdentityServer.Storage": "6.0.4",
"Microsoft.AspNetCore.Authentication.OpenIdConnect": "6.0.0"
}
},
"Duende.IdentityServer.Storage": {
"type": "Transitive",
"resolved": "6.0.4",
"contentHash": "s5gAjfbpr2IMgI+fU2Nx+2AZdzstmbt9gpo13iX7GwvqSeSaBVqj9ZskAN0R2KF1OemPdZuGnfaTcevdXMUrrw==",
"dependencies": {
"IdentityModel": "6.0.0",
"Microsoft.AspNetCore.DataProtection.Abstractions": "6.0.0"
}
},
"Fido2": { "Fido2": {
"type": "Transitive", "type": "Transitive",
"resolved": "3.0.1", "resolved": "3.0.1",
@ -259,49 +277,8 @@
}, },
"IdentityModel": { "IdentityModel": {
"type": "Transitive", "type": "Transitive",
"resolved": "4.4.0", "resolved": "6.0.0",
"contentHash": "b18wrIx5wnZlMxAX7oVsE+nDtAJ4hajYlH0xPlaRvo4r/fz08K6pPeZvbiqS9nfNbzfIgLFmNX+FL9qR9ZR5PA==", "contentHash": "eVHCR7a6m/dm5RFcBzE3qs/Jg5j9R5Rjpu8aTOv9e4AFvaQtBXb5ah7kmwU+YwA0ufRwz4wf1hnIvsD2hSnI4g=="
"dependencies": {
"Newtonsoft.Json": "11.0.2",
"System.Text.Encodings.Web": "4.7.0"
}
},
"IdentityModel.AspNetCore.OAuth2Introspection": {
"type": "Transitive",
"resolved": "4.0.1",
"contentHash": "ZNdMZMaj9fqR3j50vYsu+1U3QGd6n8+fqwf+a8mCTcmXGor+HgFDfdq0mM34bsmD6uEgAQup7sv2ZW5kR36dbA==",
"dependencies": {
"IdentityModel": "4.0.0"
}
},
"IdentityServer4": {
"type": "Transitive",
"resolved": "4.1.2",
"contentHash": "blaxxGuOA7v/w1q+fxn97wZ+x2ecG1ZD4mc/N/ZOXMNeFZZhqv+4LF26Gecyik3nWrJPmbMEtQbLmRsKG8k61w==",
"dependencies": {
"IdentityModel": "4.4.0",
"IdentityServer4.Storage": "4.1.2",
"Microsoft.AspNetCore.Authentication.OpenIdConnect": "3.1.0",
"Microsoft.IdentityModel.Protocols.OpenIdConnect": "5.6.0",
"Newtonsoft.Json": "12.0.2"
}
},
"IdentityServer4.AccessTokenValidation": {
"type": "Transitive",
"resolved": "3.0.1",
"contentHash": "qu/M6UyN4o9NVep7q545Ms7hYAnsQqSdLbN1Fjjrn4m35lyBfeQPSSNzDryAKHbodyWOQfHaOqKEyMEJQ5Rpgw==",
"dependencies": {
"IdentityModel.AspNetCore.OAuth2Introspection": "4.0.1",
"Microsoft.AspNetCore.Authentication.JwtBearer": "3.0.0"
}
},
"IdentityServer4.Storage": {
"type": "Transitive",
"resolved": "4.1.2",
"contentHash": "KoSffyZyyeCNTIyJiZnCuPakJ1QbCHlpty6gbWUj/7yl+w0PXIchgmmJnJSvddzBb8iZ2xew/vGlxWUIP17P2g==",
"dependencies": {
"IdentityModel": "4.4.0"
}
}, },
"LaunchDarkly.Cache": { "LaunchDarkly.Cache": {
"type": "Transitive", "type": "Transitive",
@ -393,10 +370,10 @@
}, },
"Microsoft.AspNetCore.Authentication.OpenIdConnect": { "Microsoft.AspNetCore.Authentication.OpenIdConnect": {
"type": "Transitive", "type": "Transitive",
"resolved": "3.1.0", "resolved": "6.0.0",
"contentHash": "O1cAQYUTU8EfRqwc5/rfTns4E4hKlFlg59fuKRrST+PzsxI6H07KqRN/JjdYhAuVYxF8jPnIGbj+zuc5paOWUw==", "contentHash": "cJxdro36spFzk/K2OFCddM6vZ+yoj6ug8mTFRH3Gdv1Pul/buSuCtfb/FSCp31UmS5S4C1315dU7wX3ErLFuDg==",
"dependencies": { "dependencies": {
"Microsoft.IdentityModel.Protocols.OpenIdConnect": "5.5.0" "Microsoft.IdentityModel.Protocols.OpenIdConnect": "6.10.0"
} }
}, },
"Microsoft.AspNetCore.Cryptography.Internal": { "Microsoft.AspNetCore.Cryptography.Internal": {
@ -429,8 +406,8 @@
}, },
"Microsoft.AspNetCore.DataProtection.Abstractions": { "Microsoft.AspNetCore.DataProtection.Abstractions": {
"type": "Transitive", "type": "Transitive",
"resolved": "3.1.32", "resolved": "6.0.0",
"contentHash": "MPL4iVyiaRxnOUY5VATHjvhDWaAEFb77KFiUxVRklv3Z3v+STofUr1UG/aCt1O9cgN7FVTDaC5A7U+zsLub8Xg==" "contentHash": "Z/UU4NEBm5UgNufJmw+j5baW26ytCOIZ0G7sZocPaOzsUeBon1bkM3lSMNZQG2GmDjAIVP2XMSODf2jzSGbibw=="
}, },
"Microsoft.Azure.Amqp": { "Microsoft.Azure.Amqp": {
"type": "Transitive", "type": "Transitive",
@ -2808,15 +2785,15 @@
"commercial.core": { "commercial.core": {
"type": "Project", "type": "Project",
"dependencies": { "dependencies": {
"Core": "[2023.10.2, )" "Core": "[2023.10.3, )"
} }
}, },
"commercial.infrastructure.entityframework": { "commercial.infrastructure.entityframework": {
"type": "Project", "type": "Project",
"dependencies": { "dependencies": {
"AutoMapper.Extensions.Microsoft.DependencyInjection": "[12.0.1, )", "AutoMapper.Extensions.Microsoft.DependencyInjection": "[12.0.1, )",
"Core": "[2023.10.2, )", "Core": "[2023.10.3, )",
"Infrastructure.EntityFramework": "[2023.10.2, )" "Infrastructure.EntityFramework": "[2023.10.3, )"
} }
}, },
"core": { "core": {
@ -2834,10 +2811,9 @@
"BitPay.Light": "[1.0.1907, )", "BitPay.Light": "[1.0.1907, )",
"Braintree": "[5.19.0, )", "Braintree": "[5.19.0, )",
"DnsClient": "[1.7.0, )", "DnsClient": "[1.7.0, )",
"Duende.IdentityServer": "[6.0.4, )",
"Fido2.AspNet": "[3.0.1, )", "Fido2.AspNet": "[3.0.1, )",
"Handlebars.Net": "[2.1.2, )", "Handlebars.Net": "[2.1.2, )",
"IdentityServer4": "[4.1.2, )",
"IdentityServer4.AccessTokenValidation": "[3.0.1, )",
"LaunchDarkly.ServerSdk": "[8.0.0, )", "LaunchDarkly.ServerSdk": "[8.0.0, )",
"MailKit": "[4.2.0, )", "MailKit": "[4.2.0, )",
"Microsoft.AspNetCore.Authentication.JwtBearer": "[6.0.4, )", "Microsoft.AspNetCore.Authentication.JwtBearer": "[6.0.4, )",
@ -2865,7 +2841,7 @@
"infrastructure.dapper": { "infrastructure.dapper": {
"type": "Project", "type": "Project",
"dependencies": { "dependencies": {
"Core": "[2023.10.2, )", "Core": "[2023.10.3, )",
"Dapper": "[2.0.123, )" "Dapper": "[2.0.123, )"
} }
}, },
@ -2873,7 +2849,7 @@
"type": "Project", "type": "Project",
"dependencies": { "dependencies": {
"AutoMapper.Extensions.Microsoft.DependencyInjection": "[12.0.1, )", "AutoMapper.Extensions.Microsoft.DependencyInjection": "[12.0.1, )",
"Core": "[2023.10.2, )", "Core": "[2023.10.3, )",
"Microsoft.EntityFrameworkCore.Relational": "[7.0.5, )", "Microsoft.EntityFrameworkCore.Relational": "[7.0.5, )",
"Microsoft.EntityFrameworkCore.SqlServer": "[7.0.5, )", "Microsoft.EntityFrameworkCore.SqlServer": "[7.0.5, )",
"Microsoft.EntityFrameworkCore.Sqlite": "[7.0.5, )", "Microsoft.EntityFrameworkCore.Sqlite": "[7.0.5, )",
@ -2885,7 +2861,7 @@
"migrator": { "migrator": {
"type": "Project", "type": "Project",
"dependencies": { "dependencies": {
"Core": "[2023.10.2, )", "Core": "[2023.10.3, )",
"Microsoft.Extensions.Logging": "[6.0.0, )", "Microsoft.Extensions.Logging": "[6.0.0, )",
"dbup-sqlserver": "[5.0.8, )" "dbup-sqlserver": "[5.0.8, )"
} }
@ -2893,30 +2869,30 @@
"mysqlmigrations": { "mysqlmigrations": {
"type": "Project", "type": "Project",
"dependencies": { "dependencies": {
"Core": "[2023.10.2, )", "Core": "[2023.10.3, )",
"Infrastructure.EntityFramework": "[2023.10.2, )" "Infrastructure.EntityFramework": "[2023.10.3, )"
} }
}, },
"postgresmigrations": { "postgresmigrations": {
"type": "Project", "type": "Project",
"dependencies": { "dependencies": {
"Core": "[2023.10.2, )", "Core": "[2023.10.3, )",
"Infrastructure.EntityFramework": "[2023.10.2, )" "Infrastructure.EntityFramework": "[2023.10.3, )"
} }
}, },
"sharedweb": { "sharedweb": {
"type": "Project", "type": "Project",
"dependencies": { "dependencies": {
"Core": "[2023.10.2, )", "Core": "[2023.10.3, )",
"Infrastructure.Dapper": "[2023.10.2, )", "Infrastructure.Dapper": "[2023.10.3, )",
"Infrastructure.EntityFramework": "[2023.10.2, )" "Infrastructure.EntityFramework": "[2023.10.3, )"
} }
}, },
"sqlitemigrations": { "sqlitemigrations": {
"type": "Project", "type": "Project",
"dependencies": { "dependencies": {
"Core": "[2023.10.2, )", "Core": "[2023.10.3, )",
"Infrastructure.EntityFramework": "[2023.10.2, )" "Infrastructure.EntityFramework": "[2023.10.3, )"
} }
} }
} }

View File

@ -5,6 +5,8 @@ using Bit.Api.Models.Response;
using Bit.Api.Utilities; using Bit.Api.Utilities;
using Bit.Api.Vault.AuthorizationHandlers.OrganizationUsers; using Bit.Api.Vault.AuthorizationHandlers.OrganizationUsers;
using Bit.Core; using Bit.Core;
using Bit.Core.AdminConsole.Enums;
using Bit.Core.AdminConsole.Models.Data.Organizations.Policies;
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.Interfaces; using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.Interfaces;
using Bit.Core.AdminConsole.Repositories; using Bit.Core.AdminConsole.Repositories;
using Bit.Core.Context; using Bit.Core.Context;
@ -12,7 +14,6 @@ using Bit.Core.Enums;
using Bit.Core.Exceptions; using Bit.Core.Exceptions;
using Bit.Core.Models.Business; using Bit.Core.Models.Business;
using Bit.Core.Models.Data.Organizations.OrganizationUsers; using Bit.Core.Models.Data.Organizations.OrganizationUsers;
using Bit.Core.Models.Data.Organizations.Policies;
using Bit.Core.OrganizationFeatures.OrganizationSubscriptions.Interface; using Bit.Core.OrganizationFeatures.OrganizationSubscriptions.Interface;
using Bit.Core.OrganizationFeatures.OrganizationUsers.Interfaces; using Bit.Core.OrganizationFeatures.OrganizationUsers.Interfaces;
using Bit.Core.Repositories; using Bit.Core.Repositories;

View File

@ -11,6 +11,8 @@ using Bit.Api.Models.Request.Accounts;
using Bit.Api.Models.Request.Organizations; using Bit.Api.Models.Request.Organizations;
using Bit.Api.Models.Response; using Bit.Api.Models.Response;
using Bit.Core; using Bit.Core;
using Bit.Core.AdminConsole.Enums;
using Bit.Core.AdminConsole.Models.Data.Organizations.Policies;
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationApiKeys.Interfaces; using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationApiKeys.Interfaces;
using Bit.Core.AdminConsole.Repositories; using Bit.Core.AdminConsole.Repositories;
using Bit.Core.Auth.Enums; using Bit.Core.Auth.Enums;
@ -20,7 +22,6 @@ using Bit.Core.Context;
using Bit.Core.Enums; using Bit.Core.Enums;
using Bit.Core.Exceptions; using Bit.Core.Exceptions;
using Bit.Core.Models.Business; using Bit.Core.Models.Business;
using Bit.Core.Models.Data.Organizations.Policies;
using Bit.Core.OrganizationFeatures.OrganizationLicenses.Interfaces; using Bit.Core.OrganizationFeatures.OrganizationLicenses.Interfaces;
using Bit.Core.OrganizationFeatures.OrganizationSubscriptions.Interface; using Bit.Core.OrganizationFeatures.OrganizationSubscriptions.Interface;
using Bit.Core.Repositories; using Bit.Core.Repositories;
@ -794,7 +795,7 @@ public class OrganizationsController : Controller
throw new NotFoundException(); throw new NotFoundException();
} }
await _organizationService.UpdateAsync(model.ToOrganization(organization)); await _organizationService.UpdateAsync(model.ToOrganization(organization), eventType: EventType.Organization_CollectionManagement_Updated);
return new OrganizationResponseModel(organization); return new OrganizationResponseModel(organization);
} }

View File

@ -1,10 +1,13 @@
using Bit.Api.AdminConsole.Models.Request; using Bit.Api.AdminConsole.Models.Request;
using Bit.Api.Models.Response; using Bit.Api.Models.Response;
using Bit.Core.AdminConsole.Enums;
using Bit.Core.AdminConsole.Models.Api.Response;
using Bit.Core.AdminConsole.Repositories;
using Bit.Core.AdminConsole.Services;
using Bit.Core.Auth.Models.Business.Tokenables; using Bit.Core.Auth.Models.Business.Tokenables;
using Bit.Core.Context; using Bit.Core.Context;
using Bit.Core.Enums; using Bit.Core.Enums;
using Bit.Core.Exceptions; using Bit.Core.Exceptions;
using Bit.Core.Models.Api.Response;
using Bit.Core.Repositories; using Bit.Core.Repositories;
using Bit.Core.Services; using Bit.Core.Services;
using Bit.Core.Settings; using Bit.Core.Settings;

View File

@ -1,7 +1,7 @@
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using System.Text.Json; using System.Text.Json;
using Bit.Core.Entities; using Bit.Core.AdminConsole.Entities;
using Bit.Core.Enums; using Bit.Core.AdminConsole.Enums;
namespace Bit.Api.AdminConsole.Models.Request; namespace Bit.Api.AdminConsole.Models.Request;

View File

@ -2,9 +2,10 @@
using Bit.Api.AdminConsole.Public.Models.Request; using Bit.Api.AdminConsole.Public.Models.Request;
using Bit.Api.AdminConsole.Public.Models.Response; using Bit.Api.AdminConsole.Public.Models.Response;
using Bit.Api.Models.Public.Response; using Bit.Api.Models.Public.Response;
using Bit.Core.AdminConsole.Enums;
using Bit.Core.AdminConsole.Repositories;
using Bit.Core.AdminConsole.Services;
using Bit.Core.Context; using Bit.Core.Context;
using Bit.Core.Enums;
using Bit.Core.Repositories;
using Bit.Core.Services; using Bit.Core.Services;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;

View File

@ -1,5 +1,5 @@
using System.Text.Json; using System.Text.Json;
using Bit.Core.Entities; using Bit.Core.AdminConsole.Entities;
namespace Bit.Api.AdminConsole.Public.Models.Request; namespace Bit.Api.AdminConsole.Public.Models.Request;

View File

@ -1,8 +1,8 @@
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using System.Text.Json; using System.Text.Json;
using Bit.Api.Models.Public.Response; using Bit.Api.Models.Public.Response;
using Bit.Core.Entities; using Bit.Core.AdminConsole.Entities;
using Bit.Core.Enums; using Bit.Core.AdminConsole.Enums;
namespace Bit.Api.AdminConsole.Public.Models.Response; namespace Bit.Api.AdminConsole.Public.Models.Response;

View File

@ -3,10 +3,10 @@ using Bit.Api.Auth.Models.Request;
using Bit.Api.Auth.Models.Response; using Bit.Api.Auth.Models.Response;
using Bit.Api.Models.Response; using Bit.Api.Models.Response;
using Bit.Api.Vault.Models.Response; using Bit.Api.Vault.Models.Response;
using Bit.Core.AdminConsole.Entities;
using Bit.Core.AdminConsole.Models.Api.Response;
using Bit.Core.Auth.Services; using Bit.Core.Auth.Services;
using Bit.Core.Entities;
using Bit.Core.Exceptions; using Bit.Core.Exceptions;
using Bit.Core.Models.Api.Response;
using Bit.Core.Repositories; using Bit.Core.Repositories;
using Bit.Core.Services; using Bit.Core.Services;
using Bit.Core.Settings; using Bit.Core.Settings;

View File

@ -3,9 +3,10 @@ using Bit.Api.Auth.Models.Request.Webauthn;
using Bit.Api.Auth.Models.Response.WebAuthn; using Bit.Api.Auth.Models.Response.WebAuthn;
using Bit.Api.Models.Response; using Bit.Api.Models.Response;
using Bit.Core; using Bit.Core;
using Bit.Core.AdminConsole.Enums;
using Bit.Core.AdminConsole.Services;
using Bit.Core.Auth.Models.Business.Tokenables; using Bit.Core.Auth.Models.Business.Tokenables;
using Bit.Core.Auth.Repositories; using Bit.Core.Auth.Repositories;
using Bit.Core.Enums;
using Bit.Core.Exceptions; using Bit.Core.Exceptions;
using Bit.Core.Services; using Bit.Core.Services;
using Bit.Core.Tokens; using Bit.Core.Tokens;

View File

@ -7,6 +7,7 @@ using Bit.Api.Utilities;
using Bit.Core; using Bit.Core;
using Bit.Core.AdminConsole.Enums.Provider; using Bit.Core.AdminConsole.Enums.Provider;
using Bit.Core.AdminConsole.Repositories; using Bit.Core.AdminConsole.Repositories;
using Bit.Core.AdminConsole.Services;
using Bit.Core.Auth.Models.Api.Request.Accounts; using Bit.Core.Auth.Models.Api.Request.Accounts;
using Bit.Core.Auth.Models.Api.Response.Accounts; using Bit.Core.Auth.Models.Api.Response.Accounts;
using Bit.Core.Auth.Models.Data; using Bit.Core.Auth.Models.Data;

View File

@ -43,12 +43,12 @@ public class DomainsResponseModel : ResponseModel
IEnumerable<GlobalEquivalentDomainsType> excludedDomains, IEnumerable<GlobalEquivalentDomainsType> excludedDomains,
bool excluded) bool excluded)
{ {
Type = globalDomain; Type = (byte)globalDomain;
Domains = domains; Domains = domains;
Excluded = excluded && (excludedDomains?.Contains(globalDomain) ?? false); Excluded = excluded && (excludedDomains?.Contains(globalDomain) ?? false);
} }
public GlobalEquivalentDomainsType Type { get; set; } public byte Type { get; set; }
public IEnumerable<string> Domains { get; set; } public IEnumerable<string> Domains { get; set; }
public bool Excluded { get; set; } public bool Excluded { get; set; }
} }

View File

@ -31,8 +31,8 @@ public class Program
return e.Level >= globalSettings.MinLogLevel.ApiSettings.IpRateLimit; return e.Level >= globalSettings.MinLogLevel.ApiSettings.IpRateLimit;
} }
if (context.Contains("IdentityServer4.Validation.TokenValidator") || if (context.Contains("Duende.IdentityServer.Validation.TokenValidator") ||
context.Contains("IdentityServer4.Validation.TokenRequestValidator")) context.Contains("Duende.IdentityServer.Validation.TokenRequestValidator"))
{ {
return e.Level >= globalSettings.MinLogLevel.ApiSettings.IdentityToken; return e.Level >= globalSettings.MinLogLevel.ApiSettings.IdentityToken;
} }

View File

@ -36,12 +36,12 @@ public class SMImportRequestModel
[Required] [Required]
[EncryptedString] [EncryptedString]
[EncryptedStringLength(1000)] [EncryptedStringLength(35000)]
public string Value { get; set; } public string Value { get; set; }
[Required] [Required]
[EncryptedString] [EncryptedString]
[EncryptedStringLength(1000)] [EncryptedStringLength(10000)]
public string Note { get; set; } public string Note { get; set; }
[Required] [Required]

View File

@ -1,4 +1,5 @@
using Bit.Core; #nullable enable
using Bit.Core;
using Bit.Core.Context; using Bit.Core.Context;
using Bit.Core.Entities; using Bit.Core.Entities;
using Bit.Core.Enums; using Bit.Core.Enums;
@ -19,6 +20,7 @@ public class BulkCollectionAuthorizationHandler : BulkAuthorizationHandler<Colle
private readonly ICurrentContext _currentContext; private readonly ICurrentContext _currentContext;
private readonly ICollectionRepository _collectionRepository; private readonly ICollectionRepository _collectionRepository;
private readonly IFeatureService _featureService; private readonly IFeatureService _featureService;
private Guid _targetOrganizationId;
private bool UseFlexibleCollections => _featureService.IsEnabled(FeatureFlagKeys.FlexibleCollections, _currentContext); private bool UseFlexibleCollections => _featureService.IsEnabled(FeatureFlagKeys.FlexibleCollections, _currentContext);
@ -33,7 +35,7 @@ public class BulkCollectionAuthorizationHandler : BulkAuthorizationHandler<Colle
} }
protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context,
CollectionOperationRequirement requirement, ICollection<Collection> resources) CollectionOperationRequirement requirement, ICollection<Collection>? resources)
{ {
if (!UseFlexibleCollections) if (!UseFlexibleCollections)
{ {
@ -41,6 +43,13 @@ public class BulkCollectionAuthorizationHandler : BulkAuthorizationHandler<Colle
throw new FeatureUnavailableException("Flexible collections is OFF when it should be ON."); throw new FeatureUnavailableException("Flexible collections is OFF when it should be ON.");
} }
// Establish pattern of authorization handler null checking passed resources
if (resources == null || !resources.Any())
{
context.Fail();
return;
}
// Acting user is not authenticated, fail // Acting user is not authenticated, fail
if (!_currentContext.UserId.HasValue) if (!_currentContext.UserId.HasValue)
{ {
@ -48,31 +57,15 @@ public class BulkCollectionAuthorizationHandler : BulkAuthorizationHandler<Colle
return; return;
} }
// Establish pattern of authorization handler null checking passed resources _targetOrganizationId = resources.First().OrganizationId;
if (resources == null || !resources.Any())
{
return;
}
var targetOrganizationId = resources.FirstOrDefault()?.OrganizationId ?? default;
if (targetOrganizationId == default)
{
return;
}
// Ensure all target collections belong to the same organization // Ensure all target collections belong to the same organization
if (resources.Any(tc => tc.OrganizationId != targetOrganizationId)) if (resources.Any(tc => tc.OrganizationId != _targetOrganizationId))
{ {
throw new BadRequestException("Requested collections must belong to the same organization."); throw new BadRequestException("Requested collections must belong to the same organization.");
} }
// Acting user is not a member of the target organization, fail var org = _currentContext.GetOrganization(_targetOrganizationId);
var org = _currentContext.GetOrganization(targetOrganizationId);
if (org == null)
{
context.Fail();
return;
}
switch (requirement) switch (requirement)
{ {
@ -97,20 +90,21 @@ public class BulkCollectionAuthorizationHandler : BulkAuthorizationHandler<Colle
} }
private async Task CanCreateAsync(AuthorizationHandlerContext context, CollectionOperationRequirement requirement, private async Task CanCreateAsync(AuthorizationHandlerContext context, CollectionOperationRequirement requirement,
CurrentContextOrganization org) CurrentContextOrganization? org)
{ {
// If false, all organization members are allowed to create collections // If the limit collection management setting is disabled, allow any user to create collections
if (!org.LimitCollectionCreationDeletion) // Otherwise, Owners, Admins, and users with CreateNewCollections permission can always create collections
if (org is
{ LimitCollectionCreationDeletion: false } or
{ Type: OrganizationUserType.Owner or OrganizationUserType.Admin } or
{ Permissions.CreateNewCollections: true })
{ {
context.Succeed(requirement); context.Succeed(requirement);
return; return;
} }
// Owners, Admins, Providers, and users with CreateNewCollections permission can always create collections // Allow provider users to create collections if they are a provider for the target organization
if ( if (await _currentContext.ProviderUserForOrgAsync(_targetOrganizationId))
org.Type is OrganizationUserType.Owner or OrganizationUserType.Admin ||
org.Permissions is { CreateNewCollections: true } ||
await _currentContext.ProviderUserForOrgAsync(org.Id))
{ {
context.Succeed(requirement); context.Succeed(requirement);
} }
@ -135,27 +129,31 @@ public class BulkCollectionAuthorizationHandler : BulkAuthorizationHandler<Colle
} }
private async Task CanDeleteAsync(AuthorizationHandlerContext context, CollectionOperationRequirement requirement, private async Task CanDeleteAsync(AuthorizationHandlerContext context, CollectionOperationRequirement requirement,
ICollection<Collection> targetCollections, CurrentContextOrganization org) ICollection<Collection> resources, CurrentContextOrganization? org)
{ {
// Owners, Admins, Providers, and users with DeleteAnyCollection permission can always delete collections // Owners, Admins, and users with DeleteAnyCollection permission can always delete collections
if ( if (org is
org.Type is OrganizationUserType.Owner or OrganizationUserType.Admin || { Type: OrganizationUserType.Owner or OrganizationUserType.Admin } or
org.Permissions is { DeleteAnyCollection: true } || { Permissions.DeleteAnyCollection: true })
await _currentContext.ProviderUserForOrgAsync(org.Id))
{ {
context.Succeed(requirement); context.Succeed(requirement);
return; return;
} }
// The limit collection management setting is enabled and we are not an Admin (above condition), fail // The limit collection management setting is disabled,
if (org.LimitCollectionCreationDeletion) // ensure acting user has manage permissions for all collections being deleted
if (org is { LimitCollectionCreationDeletion: false })
{ {
context.Fail(); var canManageCollections = await HasCollectionAccessAsync(resources, org, requireManagePermission: true);
if (canManageCollections)
{
context.Succeed(requirement);
return; return;
} }
}
var canManageCollections = await HasCollectionAccessAsync(targetCollections, org, requireManagePermission: true); // Allow providers to delete collections if they are a provider for the target organization
if (canManageCollections) if (await _currentContext.ProviderUserForOrgAsync(_targetOrganizationId))
{ {
context.Succeed(requirement); context.Succeed(requirement);
} }
@ -165,20 +163,32 @@ public class BulkCollectionAuthorizationHandler : BulkAuthorizationHandler<Colle
/// Ensures the acting user is allowed to manage access permissions for the target collections. /// Ensures the acting user is allowed to manage access permissions for the target collections.
/// </summary> /// </summary>
private async Task CanManageCollectionAccessAsync(AuthorizationHandlerContext context, private async Task CanManageCollectionAccessAsync(AuthorizationHandlerContext context,
IAuthorizationRequirement requirement, ICollection<Collection> targetCollections, CurrentContextOrganization org) IAuthorizationRequirement requirement, ICollection<Collection> resources,
CurrentContextOrganization? org)
{ {
// Owners, Admins, Providers, and users with EditAnyCollection permission can always manage collection access // Owners, Admins, and users with EditAnyCollection permission can always manage collection access
if ( if (org is
org.Permissions is { EditAnyCollection: true } || { Type: OrganizationUserType.Owner or OrganizationUserType.Admin } or
org.Type is OrganizationUserType.Owner or OrganizationUserType.Admin || { Permissions.EditAnyCollection: true })
await _currentContext.ProviderUserForOrgAsync(org.Id))
{ {
context.Succeed(requirement); context.Succeed(requirement);
return; return;
} }
var canManageCollections = await HasCollectionAccessAsync(targetCollections, org, requireManagePermission: true); // The limit collection management setting is disabled,
// ensure acting user has manage permissions for all collections being deleted
if (org is { LimitCollectionCreationDeletion: false })
{
var canManageCollections = await HasCollectionAccessAsync(resources, org, requireManagePermission: true);
if (canManageCollections) if (canManageCollections)
{
context.Succeed(requirement);
return;
}
}
// Allow providers to manage collections if they are a provider for the target organization
if (await _currentContext.ProviderUserForOrgAsync(_targetOrganizationId))
{ {
context.Succeed(requirement); context.Succeed(requirement);
} }

View File

@ -1,4 +1,5 @@
using Bit.Core; #nullable enable
using Bit.Core;
using Bit.Core.Context; using Bit.Core.Context;
using Bit.Core.Enums; using Bit.Core.Enums;
using Bit.Core.Exceptions; using Bit.Core.Exceptions;
@ -15,6 +16,7 @@ public class CollectionAuthorizationHandler : AuthorizationHandler<CollectionOpe
{ {
private readonly ICurrentContext _currentContext; private readonly ICurrentContext _currentContext;
private readonly IFeatureService _featureService; private readonly IFeatureService _featureService;
private Guid _targetOrganizationId;
private bool UseFlexibleCollections => _featureService.IsEnabled(FeatureFlagKeys.FlexibleCollections, _currentContext); private bool UseFlexibleCollections => _featureService.IsEnabled(FeatureFlagKeys.FlexibleCollections, _currentContext);
@ -44,6 +46,7 @@ public class CollectionAuthorizationHandler : AuthorizationHandler<CollectionOpe
if (requirement.OrganizationId == default) if (requirement.OrganizationId == default)
{ {
context.Fail();
return; return;
} }

View File

@ -1,4 +1,5 @@
using Bit.Api.Vault.Models.Response; using Bit.Api.Vault.Models.Response;
using Bit.Core.AdminConsole.Entities;
using Bit.Core.AdminConsole.Enums.Provider; using Bit.Core.AdminConsole.Enums.Provider;
using Bit.Core.AdminConsole.Repositories; using Bit.Core.AdminConsole.Repositories;
using Bit.Core.Entities; using Bit.Core.Entities;

View File

@ -18,6 +18,7 @@ public class CipherFido2CredentialModel
RpId = data.RpId; RpId = data.RpId;
RpName = data.RpName; RpName = data.RpName;
UserHandle = data.UserHandle; UserHandle = data.UserHandle;
UserName = data.UserName;
UserDisplayName = data.UserDisplayName; UserDisplayName = data.UserDisplayName;
Counter = data.Counter; Counter = data.Counter;
Discoverable = data.Discoverable; Discoverable = data.Discoverable;
@ -50,6 +51,9 @@ public class CipherFido2CredentialModel
public string UserHandle { get; set; } public string UserHandle { get; set; }
[EncryptedString] [EncryptedString]
[EncryptedStringLength(1000)] [EncryptedStringLength(1000)]
public string UserName { get; set; }
[EncryptedString]
[EncryptedStringLength(1000)]
public string UserDisplayName { get; set; } public string UserDisplayName { get; set; }
[EncryptedString] [EncryptedString]
[EncryptedStringLength(1000)] [EncryptedStringLength(1000)]
@ -72,6 +76,7 @@ public class CipherFido2CredentialModel
RpId = RpId, RpId = RpId,
RpName = RpName, RpName = RpName,
UserHandle = UserHandle, UserHandle = UserHandle,
UserName = UserName,
UserDisplayName = UserDisplayName, UserDisplayName = UserDisplayName,
Counter = Counter, Counter = Counter,
Discoverable = Discoverable, Discoverable = Discoverable,

View File

@ -1,9 +1,10 @@
using Bit.Api.Models.Response; using Bit.Api.Models.Response;
using Bit.Api.Tools.Models.Response; using Bit.Api.Tools.Models.Response;
using Bit.Core.AdminConsole.Entities;
using Bit.Core.AdminConsole.Models.Api.Response;
using Bit.Core.AdminConsole.Models.Data.Provider; using Bit.Core.AdminConsole.Models.Data.Provider;
using Bit.Core.Entities; using Bit.Core.Entities;
using Bit.Core.Models.Api; using Bit.Core.Models.Api;
using Bit.Core.Models.Api.Response;
using Bit.Core.Models.Data; using Bit.Core.Models.Data;
using Bit.Core.Models.Data.Organizations.OrganizationUsers; using Bit.Core.Models.Data.Organizations.OrganizationUsers;
using Bit.Core.Settings; using Bit.Core.Settings;

View File

@ -307,6 +307,24 @@
"Microsoft.Win32.Registry": "5.0.0" "Microsoft.Win32.Registry": "5.0.0"
} }
}, },
"Duende.IdentityServer": {
"type": "Transitive",
"resolved": "6.0.4",
"contentHash": "4HVjzx1F8v5J+U7oa8RGAQGj2QzmzNSu87r18Sh+dlh10uyZZL8teAaT/FaVLDObnfItGdPFvN8mwpF/HkI3Xw==",
"dependencies": {
"Duende.IdentityServer.Storage": "6.0.4",
"Microsoft.AspNetCore.Authentication.OpenIdConnect": "6.0.0"
}
},
"Duende.IdentityServer.Storage": {
"type": "Transitive",
"resolved": "6.0.4",
"contentHash": "s5gAjfbpr2IMgI+fU2Nx+2AZdzstmbt9gpo13iX7GwvqSeSaBVqj9ZskAN0R2KF1OemPdZuGnfaTcevdXMUrrw==",
"dependencies": {
"IdentityModel": "6.0.0",
"Microsoft.AspNetCore.DataProtection.Abstractions": "6.0.0"
}
},
"Fido2": { "Fido2": {
"type": "Transitive", "type": "Transitive",
"resolved": "3.0.1", "resolved": "3.0.1",
@ -343,49 +361,8 @@
}, },
"IdentityModel": { "IdentityModel": {
"type": "Transitive", "type": "Transitive",
"resolved": "4.4.0", "resolved": "6.0.0",
"contentHash": "b18wrIx5wnZlMxAX7oVsE+nDtAJ4hajYlH0xPlaRvo4r/fz08K6pPeZvbiqS9nfNbzfIgLFmNX+FL9qR9ZR5PA==", "contentHash": "eVHCR7a6m/dm5RFcBzE3qs/Jg5j9R5Rjpu8aTOv9e4AFvaQtBXb5ah7kmwU+YwA0ufRwz4wf1hnIvsD2hSnI4g=="
"dependencies": {
"Newtonsoft.Json": "11.0.2",
"System.Text.Encodings.Web": "4.7.0"
}
},
"IdentityModel.AspNetCore.OAuth2Introspection": {
"type": "Transitive",
"resolved": "4.0.1",
"contentHash": "ZNdMZMaj9fqR3j50vYsu+1U3QGd6n8+fqwf+a8mCTcmXGor+HgFDfdq0mM34bsmD6uEgAQup7sv2ZW5kR36dbA==",
"dependencies": {
"IdentityModel": "4.0.0"
}
},
"IdentityServer4": {
"type": "Transitive",
"resolved": "4.1.2",
"contentHash": "blaxxGuOA7v/w1q+fxn97wZ+x2ecG1ZD4mc/N/ZOXMNeFZZhqv+4LF26Gecyik3nWrJPmbMEtQbLmRsKG8k61w==",
"dependencies": {
"IdentityModel": "4.4.0",
"IdentityServer4.Storage": "4.1.2",
"Microsoft.AspNetCore.Authentication.OpenIdConnect": "3.1.0",
"Microsoft.IdentityModel.Protocols.OpenIdConnect": "5.6.0",
"Newtonsoft.Json": "12.0.2"
}
},
"IdentityServer4.AccessTokenValidation": {
"type": "Transitive",
"resolved": "3.0.1",
"contentHash": "qu/M6UyN4o9NVep7q545Ms7hYAnsQqSdLbN1Fjjrn4m35lyBfeQPSSNzDryAKHbodyWOQfHaOqKEyMEJQ5Rpgw==",
"dependencies": {
"IdentityModel.AspNetCore.OAuth2Introspection": "4.0.1",
"Microsoft.AspNetCore.Authentication.JwtBearer": "3.0.0"
}
},
"IdentityServer4.Storage": {
"type": "Transitive",
"resolved": "4.1.2",
"contentHash": "KoSffyZyyeCNTIyJiZnCuPakJ1QbCHlpty6gbWUj/7yl+w0PXIchgmmJnJSvddzBb8iZ2xew/vGlxWUIP17P2g==",
"dependencies": {
"IdentityModel": "4.4.0"
}
}, },
"LaunchDarkly.Cache": { "LaunchDarkly.Cache": {
"type": "Transitive", "type": "Transitive",
@ -477,10 +454,10 @@
}, },
"Microsoft.AspNetCore.Authentication.OpenIdConnect": { "Microsoft.AspNetCore.Authentication.OpenIdConnect": {
"type": "Transitive", "type": "Transitive",
"resolved": "3.1.0", "resolved": "6.0.0",
"contentHash": "O1cAQYUTU8EfRqwc5/rfTns4E4hKlFlg59fuKRrST+PzsxI6H07KqRN/JjdYhAuVYxF8jPnIGbj+zuc5paOWUw==", "contentHash": "cJxdro36spFzk/K2OFCddM6vZ+yoj6ug8mTFRH3Gdv1Pul/buSuCtfb/FSCp31UmS5S4C1315dU7wX3ErLFuDg==",
"dependencies": { "dependencies": {
"Microsoft.IdentityModel.Protocols.OpenIdConnect": "5.5.0" "Microsoft.IdentityModel.Protocols.OpenIdConnect": "6.10.0"
} }
}, },
"Microsoft.AspNetCore.Cryptography.Internal": { "Microsoft.AspNetCore.Cryptography.Internal": {
@ -513,8 +490,8 @@
}, },
"Microsoft.AspNetCore.DataProtection.Abstractions": { "Microsoft.AspNetCore.DataProtection.Abstractions": {
"type": "Transitive", "type": "Transitive",
"resolved": "3.1.32", "resolved": "6.0.0",
"contentHash": "MPL4iVyiaRxnOUY5VATHjvhDWaAEFb77KFiUxVRklv3Z3v+STofUr1UG/aCt1O9cgN7FVTDaC5A7U+zsLub8Xg==" "contentHash": "Z/UU4NEBm5UgNufJmw+j5baW26ytCOIZ0G7sZocPaOzsUeBon1bkM3lSMNZQG2GmDjAIVP2XMSODf2jzSGbibw=="
}, },
"Microsoft.Azure.Amqp": { "Microsoft.Azure.Amqp": {
"type": "Transitive", "type": "Transitive",
@ -2788,15 +2765,15 @@
"commercial.core": { "commercial.core": {
"type": "Project", "type": "Project",
"dependencies": { "dependencies": {
"Core": "[2023.10.2, )" "Core": "[2023.10.3, )"
} }
}, },
"commercial.infrastructure.entityframework": { "commercial.infrastructure.entityframework": {
"type": "Project", "type": "Project",
"dependencies": { "dependencies": {
"AutoMapper.Extensions.Microsoft.DependencyInjection": "[12.0.1, )", "AutoMapper.Extensions.Microsoft.DependencyInjection": "[12.0.1, )",
"Core": "[2023.10.2, )", "Core": "[2023.10.3, )",
"Infrastructure.EntityFramework": "[2023.10.2, )" "Infrastructure.EntityFramework": "[2023.10.3, )"
} }
}, },
"core": { "core": {
@ -2814,10 +2791,9 @@
"BitPay.Light": "[1.0.1907, )", "BitPay.Light": "[1.0.1907, )",
"Braintree": "[5.19.0, )", "Braintree": "[5.19.0, )",
"DnsClient": "[1.7.0, )", "DnsClient": "[1.7.0, )",
"Duende.IdentityServer": "[6.0.4, )",
"Fido2.AspNet": "[3.0.1, )", "Fido2.AspNet": "[3.0.1, )",
"Handlebars.Net": "[2.1.2, )", "Handlebars.Net": "[2.1.2, )",
"IdentityServer4": "[4.1.2, )",
"IdentityServer4.AccessTokenValidation": "[3.0.1, )",
"LaunchDarkly.ServerSdk": "[8.0.0, )", "LaunchDarkly.ServerSdk": "[8.0.0, )",
"MailKit": "[4.2.0, )", "MailKit": "[4.2.0, )",
"Microsoft.AspNetCore.Authentication.JwtBearer": "[6.0.4, )", "Microsoft.AspNetCore.Authentication.JwtBearer": "[6.0.4, )",
@ -2845,7 +2821,7 @@
"infrastructure.dapper": { "infrastructure.dapper": {
"type": "Project", "type": "Project",
"dependencies": { "dependencies": {
"Core": "[2023.10.2, )", "Core": "[2023.10.3, )",
"Dapper": "[2.0.123, )" "Dapper": "[2.0.123, )"
} }
}, },
@ -2853,7 +2829,7 @@
"type": "Project", "type": "Project",
"dependencies": { "dependencies": {
"AutoMapper.Extensions.Microsoft.DependencyInjection": "[12.0.1, )", "AutoMapper.Extensions.Microsoft.DependencyInjection": "[12.0.1, )",
"Core": "[2023.10.2, )", "Core": "[2023.10.3, )",
"Microsoft.EntityFrameworkCore.Relational": "[7.0.5, )", "Microsoft.EntityFrameworkCore.Relational": "[7.0.5, )",
"Microsoft.EntityFrameworkCore.SqlServer": "[7.0.5, )", "Microsoft.EntityFrameworkCore.SqlServer": "[7.0.5, )",
"Microsoft.EntityFrameworkCore.Sqlite": "[7.0.5, )", "Microsoft.EntityFrameworkCore.Sqlite": "[7.0.5, )",
@ -2865,9 +2841,9 @@
"sharedweb": { "sharedweb": {
"type": "Project", "type": "Project",
"dependencies": { "dependencies": {
"Core": "[2023.10.2, )", "Core": "[2023.10.3, )",
"Infrastructure.Dapper": "[2023.10.2, )", "Infrastructure.Dapper": "[2023.10.3, )",
"Infrastructure.EntityFramework": "[2023.10.2, )" "Infrastructure.EntityFramework": "[2023.10.3, )"
} }
} }
} }

View File

@ -264,9 +264,16 @@ public class StripeController : Controller
await SendEmails(new List<string> { organization.BillingEmail }); await SendEmails(new List<string> { organization.BillingEmail });
var ownerEmails = await _organizationRepository.GetOwnerEmailAddressesById(organization.Id); /*
* TODO: https://bitwarden.atlassian.net/browse/PM-4862
* Disabling this as part of a hot fix. It needs to check whether the organization
* belongs to a Reseller provider and only send an email to the organization owners if it does.
* It also requires a new email template as the current one contains too much billing information.
*/
await SendEmails(ownerEmails); // var ownerEmails = await _organizationRepository.GetOwnerEmailAddressesById(organization.Id);
// await SendEmails(ownerEmails);
} }
else if (userId.HasValue) else if (userId.HasValue)
{ {

View File

@ -184,6 +184,24 @@
"Microsoft.Win32.Registry": "5.0.0" "Microsoft.Win32.Registry": "5.0.0"
} }
}, },
"Duende.IdentityServer": {
"type": "Transitive",
"resolved": "6.0.4",
"contentHash": "4HVjzx1F8v5J+U7oa8RGAQGj2QzmzNSu87r18Sh+dlh10uyZZL8teAaT/FaVLDObnfItGdPFvN8mwpF/HkI3Xw==",
"dependencies": {
"Duende.IdentityServer.Storage": "6.0.4",
"Microsoft.AspNetCore.Authentication.OpenIdConnect": "6.0.0"
}
},
"Duende.IdentityServer.Storage": {
"type": "Transitive",
"resolved": "6.0.4",
"contentHash": "s5gAjfbpr2IMgI+fU2Nx+2AZdzstmbt9gpo13iX7GwvqSeSaBVqj9ZskAN0R2KF1OemPdZuGnfaTcevdXMUrrw==",
"dependencies": {
"IdentityModel": "6.0.0",
"Microsoft.AspNetCore.DataProtection.Abstractions": "6.0.0"
}
},
"Fido2": { "Fido2": {
"type": "Transitive", "type": "Transitive",
"resolved": "3.0.1", "resolved": "3.0.1",
@ -220,49 +238,8 @@
}, },
"IdentityModel": { "IdentityModel": {
"type": "Transitive", "type": "Transitive",
"resolved": "4.4.0", "resolved": "6.0.0",
"contentHash": "b18wrIx5wnZlMxAX7oVsE+nDtAJ4hajYlH0xPlaRvo4r/fz08K6pPeZvbiqS9nfNbzfIgLFmNX+FL9qR9ZR5PA==", "contentHash": "eVHCR7a6m/dm5RFcBzE3qs/Jg5j9R5Rjpu8aTOv9e4AFvaQtBXb5ah7kmwU+YwA0ufRwz4wf1hnIvsD2hSnI4g=="
"dependencies": {
"Newtonsoft.Json": "11.0.2",
"System.Text.Encodings.Web": "4.7.0"
}
},
"IdentityModel.AspNetCore.OAuth2Introspection": {
"type": "Transitive",
"resolved": "4.0.1",
"contentHash": "ZNdMZMaj9fqR3j50vYsu+1U3QGd6n8+fqwf+a8mCTcmXGor+HgFDfdq0mM34bsmD6uEgAQup7sv2ZW5kR36dbA==",
"dependencies": {
"IdentityModel": "4.0.0"
}
},
"IdentityServer4": {
"type": "Transitive",
"resolved": "4.1.2",
"contentHash": "blaxxGuOA7v/w1q+fxn97wZ+x2ecG1ZD4mc/N/ZOXMNeFZZhqv+4LF26Gecyik3nWrJPmbMEtQbLmRsKG8k61w==",
"dependencies": {
"IdentityModel": "4.4.0",
"IdentityServer4.Storage": "4.1.2",
"Microsoft.AspNetCore.Authentication.OpenIdConnect": "3.1.0",
"Microsoft.IdentityModel.Protocols.OpenIdConnect": "5.6.0",
"Newtonsoft.Json": "12.0.2"
}
},
"IdentityServer4.AccessTokenValidation": {
"type": "Transitive",
"resolved": "3.0.1",
"contentHash": "qu/M6UyN4o9NVep7q545Ms7hYAnsQqSdLbN1Fjjrn4m35lyBfeQPSSNzDryAKHbodyWOQfHaOqKEyMEJQ5Rpgw==",
"dependencies": {
"IdentityModel.AspNetCore.OAuth2Introspection": "4.0.1",
"Microsoft.AspNetCore.Authentication.JwtBearer": "3.0.0"
}
},
"IdentityServer4.Storage": {
"type": "Transitive",
"resolved": "4.1.2",
"contentHash": "KoSffyZyyeCNTIyJiZnCuPakJ1QbCHlpty6gbWUj/7yl+w0PXIchgmmJnJSvddzBb8iZ2xew/vGlxWUIP17P2g==",
"dependencies": {
"IdentityModel": "4.4.0"
}
}, },
"LaunchDarkly.Cache": { "LaunchDarkly.Cache": {
"type": "Transitive", "type": "Transitive",
@ -354,10 +331,10 @@
}, },
"Microsoft.AspNetCore.Authentication.OpenIdConnect": { "Microsoft.AspNetCore.Authentication.OpenIdConnect": {
"type": "Transitive", "type": "Transitive",
"resolved": "3.1.0", "resolved": "6.0.0",
"contentHash": "O1cAQYUTU8EfRqwc5/rfTns4E4hKlFlg59fuKRrST+PzsxI6H07KqRN/JjdYhAuVYxF8jPnIGbj+zuc5paOWUw==", "contentHash": "cJxdro36spFzk/K2OFCddM6vZ+yoj6ug8mTFRH3Gdv1Pul/buSuCtfb/FSCp31UmS5S4C1315dU7wX3ErLFuDg==",
"dependencies": { "dependencies": {
"Microsoft.IdentityModel.Protocols.OpenIdConnect": "5.5.0" "Microsoft.IdentityModel.Protocols.OpenIdConnect": "6.10.0"
} }
}, },
"Microsoft.AspNetCore.Cryptography.Internal": { "Microsoft.AspNetCore.Cryptography.Internal": {
@ -390,8 +367,8 @@
}, },
"Microsoft.AspNetCore.DataProtection.Abstractions": { "Microsoft.AspNetCore.DataProtection.Abstractions": {
"type": "Transitive", "type": "Transitive",
"resolved": "3.1.32", "resolved": "6.0.0",
"contentHash": "MPL4iVyiaRxnOUY5VATHjvhDWaAEFb77KFiUxVRklv3Z3v+STofUr1UG/aCt1O9cgN7FVTDaC5A7U+zsLub8Xg==" "contentHash": "Z/UU4NEBm5UgNufJmw+j5baW26ytCOIZ0G7sZocPaOzsUeBon1bkM3lSMNZQG2GmDjAIVP2XMSODf2jzSGbibw=="
}, },
"Microsoft.Azure.Amqp": { "Microsoft.Azure.Amqp": {
"type": "Transitive", "type": "Transitive",
@ -2617,10 +2594,9 @@
"BitPay.Light": "[1.0.1907, )", "BitPay.Light": "[1.0.1907, )",
"Braintree": "[5.19.0, )", "Braintree": "[5.19.0, )",
"DnsClient": "[1.7.0, )", "DnsClient": "[1.7.0, )",
"Duende.IdentityServer": "[6.0.4, )",
"Fido2.AspNet": "[3.0.1, )", "Fido2.AspNet": "[3.0.1, )",
"Handlebars.Net": "[2.1.2, )", "Handlebars.Net": "[2.1.2, )",
"IdentityServer4": "[4.1.2, )",
"IdentityServer4.AccessTokenValidation": "[3.0.1, )",
"LaunchDarkly.ServerSdk": "[8.0.0, )", "LaunchDarkly.ServerSdk": "[8.0.0, )",
"MailKit": "[4.2.0, )", "MailKit": "[4.2.0, )",
"Microsoft.AspNetCore.Authentication.JwtBearer": "[6.0.4, )", "Microsoft.AspNetCore.Authentication.JwtBearer": "[6.0.4, )",
@ -2648,7 +2624,7 @@
"infrastructure.dapper": { "infrastructure.dapper": {
"type": "Project", "type": "Project",
"dependencies": { "dependencies": {
"Core": "[2023.10.2, )", "Core": "[2023.10.3, )",
"Dapper": "[2.0.123, )" "Dapper": "[2.0.123, )"
} }
}, },
@ -2656,7 +2632,7 @@
"type": "Project", "type": "Project",
"dependencies": { "dependencies": {
"AutoMapper.Extensions.Microsoft.DependencyInjection": "[12.0.1, )", "AutoMapper.Extensions.Microsoft.DependencyInjection": "[12.0.1, )",
"Core": "[2023.10.2, )", "Core": "[2023.10.3, )",
"Microsoft.EntityFrameworkCore.Relational": "[7.0.5, )", "Microsoft.EntityFrameworkCore.Relational": "[7.0.5, )",
"Microsoft.EntityFrameworkCore.SqlServer": "[7.0.5, )", "Microsoft.EntityFrameworkCore.SqlServer": "[7.0.5, )",
"Microsoft.EntityFrameworkCore.Sqlite": "[7.0.5, )", "Microsoft.EntityFrameworkCore.Sqlite": "[7.0.5, )",
@ -2668,9 +2644,9 @@
"sharedweb": { "sharedweb": {
"type": "Project", "type": "Project",
"dependencies": { "dependencies": {
"Core": "[2023.10.2, )", "Core": "[2023.10.3, )",
"Infrastructure.Dapper": "[2023.10.2, )", "Infrastructure.Dapper": "[2023.10.3, )",
"Infrastructure.EntityFramework": "[2023.10.2, )" "Infrastructure.EntityFramework": "[2023.10.3, )"
} }
} }
} }

View File

@ -1,8 +1,9 @@
using Bit.Core.Enums; using Bit.Core.AdminConsole.Enums;
using Bit.Core.Models.Data.Organizations.Policies; using Bit.Core.AdminConsole.Models.Data.Organizations.Policies;
using Bit.Core.Entities;
using Bit.Core.Utilities; using Bit.Core.Utilities;
namespace Bit.Core.Entities; namespace Bit.Core.AdminConsole.Entities;
public class Policy : ITableObject<Guid> public class Policy : ITableObject<Guid>
{ {

View File

@ -1,4 +1,4 @@
namespace Bit.Core.Enums; namespace Bit.Core.AdminConsole.Enums;
public enum PolicyType : byte public enum PolicyType : byte
{ {

View File

@ -1,8 +1,9 @@
using System.Text.Json; using System.Text.Json;
using Bit.Core.Entities; using Bit.Core.AdminConsole.Entities;
using Bit.Core.Enums; using Bit.Core.AdminConsole.Enums;
using Bit.Core.Models.Api;
namespace Bit.Core.Models.Api.Response; namespace Bit.Core.AdminConsole.Models.Api.Response;
public class PolicyResponseModel : ResponseModel public class PolicyResponseModel : ResponseModel
{ {

View File

@ -0,0 +1,5 @@
namespace Bit.Core.AdminConsole.Models.Data.Organizations.Policies;
public interface IPolicyDataModel
{
}

View File

@ -1,4 +1,4 @@
namespace Bit.Core.Models.Data.Organizations.Policies; namespace Bit.Core.AdminConsole.Models.Data.Organizations.Policies;
public class MasterPasswordPolicyData : IPolicyDataModel public class MasterPasswordPolicyData : IPolicyDataModel
{ {

View File

@ -1,6 +1,6 @@
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
namespace Bit.Core.Models.Data.Organizations.Policies; namespace Bit.Core.AdminConsole.Models.Data.Organizations.Policies;
public class ResetPasswordDataModel : IPolicyDataModel public class ResetPasswordDataModel : IPolicyDataModel
{ {

View File

@ -1,6 +1,6 @@
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
namespace Bit.Core.Models.Data.Organizations.Policies; namespace Bit.Core.AdminConsole.Models.Data.Organizations.Policies;
public class SendOptionsPolicyData : IPolicyDataModel public class SendOptionsPolicyData : IPolicyDataModel
{ {

View File

@ -1,7 +1,8 @@
using Bit.Core.Entities; using Bit.Core.AdminConsole.Entities;
using Bit.Core.Enums; using Bit.Core.AdminConsole.Enums;
using Bit.Core.Repositories;
namespace Bit.Core.Repositories; namespace Bit.Core.AdminConsole.Repositories;
public interface IPolicyRepository : IRepository<Policy, Guid> public interface IPolicyRepository : IRepository<Policy, Guid>
{ {

View File

@ -1,9 +1,12 @@
using Bit.Core.Entities; using Bit.Core.AdminConsole.Entities;
using Bit.Core.AdminConsole.Enums;
using Bit.Core.AdminConsole.Models.Data.Organizations.Policies;
using Bit.Core.Entities;
using Bit.Core.Enums; using Bit.Core.Enums;
using Bit.Core.Models.Data.Organizations.OrganizationUsers; using Bit.Core.Models.Data.Organizations.OrganizationUsers;
using Bit.Core.Models.Data.Organizations.Policies; using Bit.Core.Services;
namespace Bit.Core.Services; namespace Bit.Core.AdminConsole.Services;
public interface IPolicyService public interface IPolicyService
{ {

View File

@ -1,14 +1,18 @@
using Bit.Core.Auth.Enums; using Bit.Core.AdminConsole.Entities;
using Bit.Core.AdminConsole.Enums;
using Bit.Core.AdminConsole.Models.Data.Organizations.Policies;
using Bit.Core.AdminConsole.Repositories;
using Bit.Core.Auth.Enums;
using Bit.Core.Auth.Repositories; using Bit.Core.Auth.Repositories;
using Bit.Core.Entities; using Bit.Core.Entities;
using Bit.Core.Enums; using Bit.Core.Enums;
using Bit.Core.Exceptions; using Bit.Core.Exceptions;
using Bit.Core.Models.Data.Organizations.OrganizationUsers; using Bit.Core.Models.Data.Organizations.OrganizationUsers;
using Bit.Core.Models.Data.Organizations.Policies;
using Bit.Core.Repositories; using Bit.Core.Repositories;
using Bit.Core.Services;
using Bit.Core.Settings; using Bit.Core.Settings;
namespace Bit.Core.Services; namespace Bit.Core.AdminConsole.Services.Implementations;
public class PolicyService : IPolicyService public class PolicyService : IPolicyService
{ {
@ -114,12 +118,12 @@ public class PolicyService : IPolicyService
var orgUsers = await _organizationUserRepository.GetManyDetailsByOrganizationAsync( var orgUsers = await _organizationUserRepository.GetManyDetailsByOrganizationAsync(
policy.OrganizationId); policy.OrganizationId);
var removableOrgUsers = orgUsers.Where(ou => var removableOrgUsers = orgUsers.Where(ou =>
ou.Status != Enums.OrganizationUserStatusType.Invited && ou.Status != Enums.OrganizationUserStatusType.Revoked && ou.Status != OrganizationUserStatusType.Invited && ou.Status != OrganizationUserStatusType.Revoked &&
ou.Type != Enums.OrganizationUserType.Owner && ou.Type != Enums.OrganizationUserType.Admin && ou.Type != OrganizationUserType.Owner && ou.Type != OrganizationUserType.Admin &&
ou.UserId != savingUserId); ou.UserId != savingUserId);
switch (policy.Type) switch (policy.Type)
{ {
case Enums.PolicyType.TwoFactorAuthentication: case PolicyType.TwoFactorAuthentication:
foreach (var orgUser in removableOrgUsers) foreach (var orgUser in removableOrgUsers)
{ {
if (!await userService.TwoFactorIsEnabledAsync(orgUser)) if (!await userService.TwoFactorIsEnabledAsync(orgUser))
@ -131,7 +135,7 @@ public class PolicyService : IPolicyService
} }
} }
break; break;
case Enums.PolicyType.SingleOrg: case PolicyType.SingleOrg:
var userOrgs = await _organizationUserRepository.GetManyByManyUsersAsync( var userOrgs = await _organizationUserRepository.GetManyByManyUsersAsync(
removableOrgUsers.Select(ou => ou.UserId.Value)); removableOrgUsers.Select(ou => ou.UserId.Value));
foreach (var orgUser in removableOrgUsers) foreach (var orgUser in removableOrgUsers)
@ -154,7 +158,7 @@ public class PolicyService : IPolicyService
} }
policy.RevisionDate = now; policy.RevisionDate = now;
await _policyRepository.UpsertAsync(policy); await _policyRepository.UpsertAsync(policy);
await _eventService.LogPolicyEventAsync(policy, Enums.EventType.Policy_Updated); await _eventService.LogPolicyEventAsync(policy, EventType.Policy_Updated);
} }
public async Task<MasterPasswordPolicyData> GetMasterPasswordPolicyForUserAsync(User user) public async Task<MasterPasswordPolicyData> GetMasterPasswordPolicyForUserAsync(User user)

View File

@ -0,0 +1,7 @@
namespace Bit.Core.Auth.Enums;
public enum WebAuthnLoginAssertionOptionsScope
{
Authentication = 0,
PrfRegistration = 1
}

View File

@ -0,0 +1,18 @@

using Bit.Core.Models.Api;
using Fido2NetLib;
namespace Bit.Core.Auth.Models.Api.Response.Accounts;
public class WebAuthnLoginAssertionOptionsResponseModel : ResponseModel
{
private const string ResponseObj = "webAuthnLoginAssertionOptions";
public WebAuthnLoginAssertionOptionsResponseModel() : base(ResponseObj)
{
}
public AssertionOptions Options { get; set; }
public string Token { get; set; }
}

View File

@ -16,6 +16,12 @@ public class UserDecryptionOptions : ResponseModel
/// </summary> /// </summary>
public bool HasMasterPassword { get; set; } public bool HasMasterPassword { get; set; }
/// <summary>
/// Gets or sets the WebAuthn PRF decryption keys.
/// </summary>
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public WebAuthnPrfDecryptionOption? WebAuthnPrfOption { get; set; }
/// <summary> /// <summary>
/// Gets or sets information regarding this users trusted device decryption setup. /// Gets or sets information regarding this users trusted device decryption setup.
/// </summary> /// </summary>
@ -29,6 +35,20 @@ public class UserDecryptionOptions : ResponseModel
public KeyConnectorUserDecryptionOption? KeyConnectorOption { get; set; } public KeyConnectorUserDecryptionOption? KeyConnectorOption { get; set; }
} }
public class WebAuthnPrfDecryptionOption
{
public string EncryptedPrivateKey { get; }
public string EncryptedUserKey { get; }
public WebAuthnPrfDecryptionOption(
string encryptedPrivateKey,
string encryptedUserKey)
{
EncryptedPrivateKey = encryptedPrivateKey;
EncryptedUserKey = encryptedUserKey;
}
}
public class TrustedDeviceUserDecryptionOption public class TrustedDeviceUserDecryptionOption
{ {
public bool HasAdminApproval { get; } public bool HasAdminApproval { get; }

View File

@ -0,0 +1,47 @@
using System.Text.Json.Serialization;
using Bit.Core.Auth.Enums;
using Bit.Core.Tokens;
using Fido2NetLib;
namespace Bit.Core.Auth.Models.Business.Tokenables;
public class WebAuthnLoginAssertionOptionsTokenable : ExpiringTokenable
{
// Lifetime 17 minutes =
// - 6 Minutes for Attestation (max webauthn timeout)
// - 6 Minutes for PRF Assertion (max webauthn timeout)
// - 5 minutes for user to complete the process (name their passkey, etc)
private static readonly TimeSpan _tokenLifetime = TimeSpan.FromMinutes(17);
public const string ClearTextPrefix = "BWWebAuthnLoginAssertionOptions_";
public const string DataProtectorPurpose = "WebAuthnLoginAssertionOptionsDataProtector";
public const string TokenIdentifier = "WebAuthnLoginAssertionOptionsToken";
public string Identifier { get; set; } = TokenIdentifier;
public AssertionOptions Options { get; set; }
public WebAuthnLoginAssertionOptionsScope Scope { get; set; }
[JsonConstructor]
public WebAuthnLoginAssertionOptionsTokenable()
{
ExpirationDate = DateTime.UtcNow.Add(_tokenLifetime);
}
public WebAuthnLoginAssertionOptionsTokenable(WebAuthnLoginAssertionOptionsScope scope, AssertionOptions options) : this()
{
Scope = scope;
Options = options;
}
public bool TokenIsValid(WebAuthnLoginAssertionOptionsScope scope)
{
if (!Valid)
{
return false;
}
return Scope == scope;
}
protected override bool TokenIsValid() => Identifier == TokenIdentifier && Options != null;
}

View File

@ -1,43 +0,0 @@
using System.Text.Json.Serialization;
using Bit.Core.Entities;
using Bit.Core.Tokens;
namespace Bit.Core.Auth.Models.Business.Tokenables;
public class WebAuthnLoginTokenable : ExpiringTokenable
{
private const double _tokenLifetimeInHours = (double)1 / 60; // 1 minute
public const string ClearTextPrefix = "BWWebAuthnLogin_";
public const string DataProtectorPurpose = "WebAuthnLoginDataProtector";
public const string TokenIdentifier = "WebAuthnLoginToken";
public string Identifier { get; set; } = TokenIdentifier;
public Guid Id { get; set; }
public string Email { get; set; }
[JsonConstructor]
public WebAuthnLoginTokenable()
{
ExpirationDate = DateTime.UtcNow.AddHours(_tokenLifetimeInHours);
}
public WebAuthnLoginTokenable(User user) : this()
{
Id = user?.Id ?? default;
Email = user?.Email;
}
public bool TokenIsValid(User user)
{
if (Id == default || Email == default || user == null)
{
return false;
}
return Id == user.Id &&
Email.Equals(user.Email, StringComparison.InvariantCultureIgnoreCase);
}
// Validates deserialized
protected override bool TokenIsValid() => Identifier == TokenIdentifier && Id != default && !string.IsNullOrWhiteSpace(Email);
}

View File

@ -1,4 +1,5 @@
using Bit.Core.Auth.Entities; using Bit.Core.AdminConsole.Entities;
using Bit.Core.Auth.Entities;
using Bit.Core.Auth.Enums; using Bit.Core.Auth.Enums;
using Bit.Core.Auth.Models.Data; using Bit.Core.Auth.Models.Data;
using Bit.Core.Entities; using Bit.Core.Entities;

View File

@ -1,4 +1,6 @@
using Bit.Core.Auth.Entities; using Bit.Core.AdminConsole.Entities;
using Bit.Core.AdminConsole.Repositories;
using Bit.Core.Auth.Entities;
using Bit.Core.Auth.Enums; using Bit.Core.Auth.Enums;
using Bit.Core.Auth.Models; using Bit.Core.Auth.Models;
using Bit.Core.Auth.Models.Business.Tokenables; using Bit.Core.Auth.Models.Business.Tokenables;

View File

@ -1,10 +1,14 @@
using Bit.Core.Auth.Entities; using Bit.Core.AdminConsole.Entities;
using Bit.Core.AdminConsole.Enums;
using Bit.Core.AdminConsole.Models.Data.Organizations.Policies;
using Bit.Core.AdminConsole.Repositories;
using Bit.Core.AdminConsole.Services;
using Bit.Core.Auth.Entities;
using Bit.Core.Auth.Enums; using Bit.Core.Auth.Enums;
using Bit.Core.Auth.Repositories; using Bit.Core.Auth.Repositories;
using Bit.Core.Entities; using Bit.Core.Entities;
using Bit.Core.Enums; using Bit.Core.Enums;
using Bit.Core.Exceptions; using Bit.Core.Exceptions;
using Bit.Core.Models.Data.Organizations.Policies;
using Bit.Core.Repositories; using Bit.Core.Repositories;
using Bit.Core.Services; using Bit.Core.Services;

View File

@ -0,0 +1,19 @@
namespace Bit.Core.Auth.Utilities;
public static class GuidUtilities
{
public static bool TryParseBytes(ReadOnlySpan<byte> bytes, out Guid guid)
{
try
{
guid = new Guid(bytes);
return true;
}
catch
{
guid = Guid.Empty;
return false;
}
}
}

View File

@ -26,18 +26,9 @@ public static class Constants
public const string CipherKeyEncryptionMinimumVersion = "2023.9.2"; public const string CipherKeyEncryptionMinimumVersion = "2023.9.2";
/// <summary> /// <summary>
/// When you set the ProrationBehavior to create_prorations, /// Used by IdentityServer to identify our own provider.
/// Stripe will automatically create prorations for any changes made to the subscription,
/// such as changing the plan, adding or removing quantities, or applying discounts.
/// </summary> /// </summary>
public const string CreateProrations = "create_prorations"; public const string IdentityProvider = "bitwarden";
/// <summary>
/// When you set the ProrationBehavior to always_invoice,
/// Stripe will always generate an invoice when a subscription update occurs,
/// regardless of whether there is a proration or not.
/// </summary>
public const string AlwaysInvoice = "always_invoice";
} }
public static class TokenPurposes public static class TokenPurposes
@ -57,6 +48,7 @@ public static class FeatureFlagKeys
public const string PasswordlessLogin = "passwordless-login"; public const string PasswordlessLogin = "passwordless-login";
public const string TrustedDeviceEncryption = "trusted-device-encryption"; public const string TrustedDeviceEncryption = "trusted-device-encryption";
public const string Fido2VaultCredentials = "fido2-vault-credentials"; public const string Fido2VaultCredentials = "fido2-vault-credentials";
public const string VaultOnboarding = "vault-onboarding";
public const string AutofillV2 = "autofill-v2"; public const string AutofillV2 = "autofill-v2";
public const string BrowserFilelessImport = "browser-fileless-import"; public const string BrowserFilelessImport = "browser-fileless-import";
public const string FlexibleCollections = "flexible-collections"; public const string FlexibleCollections = "flexible-collections";

View File

@ -31,7 +31,6 @@
<PackageReference Include="DnsClient" Version="1.7.0" /> <PackageReference Include="DnsClient" Version="1.7.0" />
<PackageReference Include="Fido2.AspNet" Version="3.0.1" /> <PackageReference Include="Fido2.AspNet" Version="3.0.1" />
<PackageReference Include="Handlebars.Net" Version="2.1.2" /> <PackageReference Include="Handlebars.Net" Version="2.1.2" />
<PackageReference Include="IdentityServer4.AccessTokenValidation" Version="3.0.1" />
<PackageReference Include="MailKit" Version="4.2.0" /> <PackageReference Include="MailKit" Version="4.2.0" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="6.0.4" /> <PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="6.0.4" />
<PackageReference Include="Microsoft.Azure.Cosmos.Table" Version="1.0.8" /> <PackageReference Include="Microsoft.Azure.Cosmos.Table" Version="1.0.8" />
@ -48,7 +47,7 @@
<PackageReference Include="Serilog.Extensions.Logging" Version="3.1.0" /> <PackageReference Include="Serilog.Extensions.Logging" Version="3.1.0" />
<PackageReference Include="Serilog.Extensions.Logging.File" Version="2.0.0" /> <PackageReference Include="Serilog.Extensions.Logging.File" Version="2.0.0" />
<PackageReference Include="Sentry.Serilog" Version="3.16.0" /> <PackageReference Include="Sentry.Serilog" Version="3.16.0" />
<PackageReference Include="IdentityServer4" Version="4.1.2" /> <PackageReference Include="Duende.IdentityServer" Version="6.0.4" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" /> <PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="Serilog.Sinks.AzureCosmosDB" Version="2.0.0" /> <PackageReference Include="Serilog.Sinks.AzureCosmosDB" Version="2.0.0" />
<PackageReference Include="Serilog.Sinks.SyslogMessages" Version="2.0.6" /> <PackageReference Include="Serilog.Sinks.SyslogMessages" Version="2.0.6" />

View File

@ -67,6 +67,7 @@ public enum EventType : int
Organization_EnabledKeyConnector = 1606, Organization_EnabledKeyConnector = 1606,
Organization_DisabledKeyConnector = 1607, Organization_DisabledKeyConnector = 1607,
Organization_SponsorshipsSynced = 1608, Organization_SponsorshipsSynced = 1608,
Organization_CollectionManagement_Updated = 1609,
Policy_Updated = 1700, Policy_Updated = 1700,

View File

@ -1,4 +1,4 @@
using IdentityServer4.Models; using Duende.IdentityServer.Models;
namespace Bit.Core.IdentityServer; namespace Bit.Core.IdentityServer;

View File

@ -1,5 +1,5 @@
using Bit.Core.Settings; using Bit.Core.Settings;
using IdentityServer4.Configuration; using Duende.IdentityServer.Configuration;
using Microsoft.AspNetCore.Authentication.Cookies; using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Caching.StackExchangeRedis; using Microsoft.Extensions.Caching.StackExchangeRedis;

View File

@ -1,4 +1,4 @@
using Bit.Core.Models.Data.Organizations.Policies; using Bit.Core.AdminConsole.Models.Data.Organizations.Policies;
namespace Bit.Core.Models.Api.Response; namespace Bit.Core.Models.Api.Response;

View File

@ -1,7 +0,0 @@
namespace Bit.Core.Models.Business;
public class InvoicePreviewResult
{
public bool IsInvoicedNow { get; set; }
public string PaymentIntentClientSecret { get; set; }
}

View File

@ -1,9 +0,0 @@
using Stripe;
namespace Bit.Core.Models.Business;
public class PendingInoviceItems
{
public IEnumerable<InvoiceItem> PendingInvoiceItems { get; set; }
public IDictionary<string, InvoiceItem> PendingInvoiceItemsDict { get; set; }
}

View File

@ -44,7 +44,7 @@ public class SecretsManagerSubscribeUpdate : SubscriptionUpdate
{ {
updatedItems.Add(new SubscriptionItemOptions updatedItems.Add(new SubscriptionItemOptions
{ {
Plan = _plan.SecretsManager.StripeSeatPlanId, Price = _plan.SecretsManager.StripeSeatPlanId,
Quantity = _additionalSeats Quantity = _additionalSeats
}); });
} }
@ -53,7 +53,7 @@ public class SecretsManagerSubscribeUpdate : SubscriptionUpdate
{ {
updatedItems.Add(new SubscriptionItemOptions updatedItems.Add(new SubscriptionItemOptions
{ {
Plan = _plan.SecretsManager.StripeServiceAccountPlanId, Price = _plan.SecretsManager.StripeServiceAccountPlanId,
Quantity = _additionalServiceAccounts Quantity = _additionalServiceAccounts
}); });
} }
@ -63,14 +63,14 @@ public class SecretsManagerSubscribeUpdate : SubscriptionUpdate
{ {
updatedItems.Add(new SubscriptionItemOptions updatedItems.Add(new SubscriptionItemOptions
{ {
Plan = _plan.SecretsManager.StripeSeatPlanId, Price = _plan.SecretsManager.StripeSeatPlanId,
Quantity = _previousSeats, Quantity = _previousSeats,
Deleted = _previousSeats == 0 ? true : (bool?)null, Deleted = _previousSeats == 0 ? true : (bool?)null,
}); });
updatedItems.Add(new SubscriptionItemOptions updatedItems.Add(new SubscriptionItemOptions
{ {
Plan = _plan.SecretsManager.StripeServiceAccountPlanId, Price = _plan.SecretsManager.StripeServiceAccountPlanId,
Quantity = _previousServiceAccounts, Quantity = _previousServiceAccounts,
Deleted = _previousServiceAccounts == 0 ? true : (bool?)null, Deleted = _previousServiceAccounts == 0 ? true : (bool?)null,
}); });

View File

@ -1,4 +1,5 @@
using Bit.Core.Enums; using Bit.Core.AdminConsole.Enums;
using Bit.Core.Enums;
namespace Bit.Core.Models.Data.Organizations.OrganizationUsers; namespace Bit.Core.Models.Data.Organizations.OrganizationUsers;

View File

@ -1,5 +0,0 @@
namespace Bit.Core.Models.Data.Organizations.Policies;
public interface IPolicyDataModel
{
}

View File

@ -1,4 +1,6 @@
using Bit.Core.AdminConsole.Models.OrganizationConnectionConfigs; using Bit.Core.AdminConsole.Entities;
using Bit.Core.AdminConsole.Enums;
using Bit.Core.AdminConsole.Models.OrganizationConnectionConfigs;
using Bit.Core.Auth.Entities; using Bit.Core.Auth.Entities;
using Bit.Core.Auth.Enums; using Bit.Core.Auth.Enums;
using Bit.Core.Entities; using Bit.Core.Entities;

View File

@ -1,4 +1,5 @@
using Bit.Core.AdminConsole.Models.OrganizationConnectionConfigs; using Bit.Core.AdminConsole.Enums;
using Bit.Core.AdminConsole.Models.OrganizationConnectionConfigs;
using Bit.Core.AdminConsole.Repositories; using Bit.Core.AdminConsole.Repositories;
using Bit.Core.Auth.Enums; using Bit.Core.Auth.Enums;
using Bit.Core.Auth.Repositories; using Bit.Core.Auth.Repositories;

View File

@ -1,4 +1,6 @@
using Bit.Core.Auth.Models.Business.Tokenables; using Bit.Core.AdminConsole.Enums;
using Bit.Core.AdminConsole.Services;
using Bit.Core.Auth.Models.Business.Tokenables;
using Bit.Core.Entities; using Bit.Core.Entities;
using Bit.Core.Enums; using Bit.Core.Enums;
using Bit.Core.Exceptions; using Bit.Core.Exceptions;

View File

@ -1,4 +1,5 @@
using Bit.Core.Entities; using Bit.Core.AdminConsole.Enums;
using Bit.Core.Entities;
using Bit.Core.Enums; using Bit.Core.Enums;
using Bit.Core.Models.Data; using Bit.Core.Models.Data;
using Bit.Core.Models.Data.Organizations.OrganizationUsers; using Bit.Core.Models.Data.Organizations.OrganizationUsers;

View File

@ -27,7 +27,7 @@ public interface IOrganizationService
Task DisableAsync(Guid organizationId, DateTime? expirationDate); Task DisableAsync(Guid organizationId, DateTime? expirationDate);
Task UpdateExpirationDateAsync(Guid organizationId, DateTime? expirationDate); Task UpdateExpirationDateAsync(Guid organizationId, DateTime? expirationDate);
Task EnableAsync(Guid organizationId); Task EnableAsync(Guid organizationId);
Task UpdateAsync(Organization organization, bool updateBilling = false); Task UpdateAsync(Organization organization, bool updateBilling = false, EventType eventType = EventType.Organization_Updated);
Task UpdateTwoFactorProviderAsync(Organization organization, TwoFactorProviderType type); Task UpdateTwoFactorProviderAsync(Organization organization, TwoFactorProviderType type);
Task DisableTwoFactorProviderAsync(Organization organization, TwoFactorProviderType type); Task DisableTwoFactorProviderAsync(Organization organization, TwoFactorProviderType type);
Task<List<OrganizationUser>> InviteUsersAsync(Guid organizationId, Guid? invitingUserId, Task<List<OrganizationUser>> InviteUsersAsync(Guid organizationId, Guid? invitingUserId,

View File

@ -1,5 +1,4 @@
using Bit.Core.Models.BitStripe; using Bit.Core.Models.BitStripe;
using Stripe;
namespace Bit.Core.Services; namespace Bit.Core.Services;
@ -15,11 +14,8 @@ public interface IStripeAdapter
Task<Stripe.Subscription> SubscriptionUpdateAsync(string id, Stripe.SubscriptionUpdateOptions options = null); Task<Stripe.Subscription> SubscriptionUpdateAsync(string id, Stripe.SubscriptionUpdateOptions options = null);
Task<Stripe.Subscription> SubscriptionCancelAsync(string Id, Stripe.SubscriptionCancelOptions options = null); Task<Stripe.Subscription> SubscriptionCancelAsync(string Id, Stripe.SubscriptionCancelOptions options = null);
Task<Stripe.Invoice> InvoiceUpcomingAsync(Stripe.UpcomingInvoiceOptions options); Task<Stripe.Invoice> InvoiceUpcomingAsync(Stripe.UpcomingInvoiceOptions options);
Task<Stripe.Invoice> InvoiceCreateAsync(Stripe.InvoiceCreateOptions options);
Task<Stripe.InvoiceItem> InvoiceItemCreateAsync(Stripe.InvoiceItemCreateOptions options);
Task<Stripe.Invoice> InvoiceGetAsync(string id, Stripe.InvoiceGetOptions options); Task<Stripe.Invoice> InvoiceGetAsync(string id, Stripe.InvoiceGetOptions options);
Task<List<Stripe.Invoice>> InvoiceListAsync(StripeInvoiceListOptions options); Task<List<Stripe.Invoice>> InvoiceListAsync(StripeInvoiceListOptions options);
IEnumerable<InvoiceItem> InvoiceItemListAsync(InvoiceItemListOptions options);
Task<Stripe.Invoice> InvoiceUpdateAsync(string id, Stripe.InvoiceUpdateOptions options); Task<Stripe.Invoice> InvoiceUpdateAsync(string id, Stripe.InvoiceUpdateOptions options);
Task<Stripe.Invoice> InvoiceFinalizeInvoiceAsync(string id, Stripe.InvoiceFinalizeOptions options); Task<Stripe.Invoice> InvoiceFinalizeInvoiceAsync(string id, Stripe.InvoiceFinalizeOptions options);
Task<Stripe.Invoice> InvoiceSendInvoiceAsync(string id, Stripe.InvoiceSendOptions options); Task<Stripe.Invoice> InvoiceSendInvoiceAsync(string id, Stripe.InvoiceSendOptions options);

View File

@ -1,4 +1,5 @@
using System.Security.Claims; using System.Security.Claims;
using Bit.Core.Auth.Entities;
using Bit.Core.Auth.Enums; using Bit.Core.Auth.Enums;
using Bit.Core.Auth.Models; using Bit.Core.Auth.Models;
using Bit.Core.Entities; using Bit.Core.Entities;
@ -29,8 +30,8 @@ public interface IUserService
Task<bool> CompleteWebAuthRegistrationAsync(User user, int value, string name, AuthenticatorAttestationRawResponse attestationResponse); Task<bool> CompleteWebAuthRegistrationAsync(User user, int value, string name, AuthenticatorAttestationRawResponse attestationResponse);
Task<CredentialCreateOptions> StartWebAuthnLoginRegistrationAsync(User user); Task<CredentialCreateOptions> StartWebAuthnLoginRegistrationAsync(User user);
Task<bool> CompleteWebAuthLoginRegistrationAsync(User user, string name, CredentialCreateOptions options, AuthenticatorAttestationRawResponse attestationResponse, bool supportsPrf, string encryptedUserKey = null, string encryptedPublicKey = null, string encryptedPrivateKey = null); Task<bool> CompleteWebAuthLoginRegistrationAsync(User user, string name, CredentialCreateOptions options, AuthenticatorAttestationRawResponse attestationResponse, bool supportsPrf, string encryptedUserKey = null, string encryptedPublicKey = null, string encryptedPrivateKey = null);
Task<AssertionOptions> StartWebAuthnLoginAssertionAsync(User user); AssertionOptions StartWebAuthnLoginAssertion();
Task<string> CompleteWebAuthLoginAssertionAsync(AuthenticatorAssertionRawResponse assertionResponse, User user); Task<(User, WebAuthnCredential)> CompleteWebAuthLoginAssertionAsync(AssertionOptions options, AuthenticatorAssertionRawResponse assertionResponse);
Task SendEmailVerificationAsync(User user); Task SendEmailVerificationAsync(User user);
Task<IdentityResult> ConfirmEmailAsync(User user, string token); Task<IdentityResult> ConfirmEmailAsync(User user, string token);
Task InitiateEmailChangeAsync(User user, string newEmail); Task InitiateEmailChangeAsync(User user, string newEmail);

View File

@ -1,10 +1,13 @@
using System.Security.Claims; using System.Security.Claims;
using System.Text.Json; using System.Text.Json;
using Bit.Core.AdminConsole.Entities; using Bit.Core.AdminConsole.Entities;
using Bit.Core.AdminConsole.Enums;
using Bit.Core.AdminConsole.Enums.Provider; using Bit.Core.AdminConsole.Enums.Provider;
using Bit.Core.AdminConsole.Models.Business; using Bit.Core.AdminConsole.Models.Business;
using Bit.Core.AdminConsole.Models.Data.Organizations.Policies;
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.Interfaces; using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.Interfaces;
using Bit.Core.AdminConsole.Repositories; using Bit.Core.AdminConsole.Repositories;
using Bit.Core.AdminConsole.Services;
using Bit.Core.Auth.Enums; using Bit.Core.Auth.Enums;
using Bit.Core.Auth.Models.Business; using Bit.Core.Auth.Models.Business;
using Bit.Core.Auth.Models.Business.Tokenables; using Bit.Core.Auth.Models.Business.Tokenables;
@ -15,7 +18,6 @@ using Bit.Core.Enums;
using Bit.Core.Exceptions; using Bit.Core.Exceptions;
using Bit.Core.Models.Business; using Bit.Core.Models.Business;
using Bit.Core.Models.Data; using Bit.Core.Models.Data;
using Bit.Core.Models.Data.Organizations.Policies;
using Bit.Core.OrganizationFeatures.OrganizationSubscriptions.Interface; using Bit.Core.OrganizationFeatures.OrganizationSubscriptions.Interface;
using Bit.Core.Repositories; using Bit.Core.Repositories;
using Bit.Core.Settings; using Bit.Core.Settings;
@ -57,6 +59,7 @@ public class OrganizationService : IOrganizationService
private readonly IProviderUserRepository _providerUserRepository; private readonly IProviderUserRepository _providerUserRepository;
private readonly ICountNewSmSeatsRequiredQuery _countNewSmSeatsRequiredQuery; private readonly ICountNewSmSeatsRequiredQuery _countNewSmSeatsRequiredQuery;
private readonly IUpdateSecretsManagerSubscriptionCommand _updateSecretsManagerSubscriptionCommand; private readonly IUpdateSecretsManagerSubscriptionCommand _updateSecretsManagerSubscriptionCommand;
private readonly IProviderRepository _providerRepository;
private readonly IOrgUserInviteTokenableFactory _orgUserInviteTokenableFactory; private readonly IOrgUserInviteTokenableFactory _orgUserInviteTokenableFactory;
private readonly IDataProtectorTokenFactory<OrgUserInviteTokenable> _orgUserInviteTokenDataFactory; private readonly IDataProtectorTokenFactory<OrgUserInviteTokenable> _orgUserInviteTokenDataFactory;
private readonly IFeatureService _featureService; private readonly IFeatureService _featureService;
@ -90,6 +93,7 @@ public class OrganizationService : IOrganizationService
IOrgUserInviteTokenableFactory orgUserInviteTokenableFactory, IOrgUserInviteTokenableFactory orgUserInviteTokenableFactory,
IDataProtectorTokenFactory<OrgUserInviteTokenable> orgUserInviteTokenDataFactory, IDataProtectorTokenFactory<OrgUserInviteTokenable> orgUserInviteTokenDataFactory,
IUpdateSecretsManagerSubscriptionCommand updateSecretsManagerSubscriptionCommand, IUpdateSecretsManagerSubscriptionCommand updateSecretsManagerSubscriptionCommand,
IProviderRepository providerRepository,
IFeatureService featureService) IFeatureService featureService)
{ {
_organizationRepository = organizationRepository; _organizationRepository = organizationRepository;
@ -118,6 +122,7 @@ public class OrganizationService : IOrganizationService
_providerUserRepository = providerUserRepository; _providerUserRepository = providerUserRepository;
_countNewSmSeatsRequiredQuery = countNewSmSeatsRequiredQuery; _countNewSmSeatsRequiredQuery = countNewSmSeatsRequiredQuery;
_updateSecretsManagerSubscriptionCommand = updateSecretsManagerSubscriptionCommand; _updateSecretsManagerSubscriptionCommand = updateSecretsManagerSubscriptionCommand;
_providerRepository = providerRepository;
_orgUserInviteTokenableFactory = orgUserInviteTokenableFactory; _orgUserInviteTokenableFactory = orgUserInviteTokenableFactory;
_orgUserInviteTokenDataFactory = orgUserInviteTokenDataFactory; _orgUserInviteTokenDataFactory = orgUserInviteTokenDataFactory;
_featureService = featureService; _featureService = featureService;
@ -736,7 +741,7 @@ public class OrganizationService : IOrganizationService
} }
} }
public async Task UpdateAsync(Organization organization, bool updateBilling = false) public async Task UpdateAsync(Organization organization, bool updateBilling = false, EventType eventType = EventType.Organization_Updated)
{ {
if (organization.Id == default(Guid)) if (organization.Id == default(Guid))
{ {
@ -752,7 +757,7 @@ public class OrganizationService : IOrganizationService
} }
} }
await ReplaceAndUpdateCacheAsync(organization, EventType.Organization_Updated); await ReplaceAndUpdateCacheAsync(organization, eventType);
if (updateBilling && !string.IsNullOrWhiteSpace(organization.GatewayCustomerId)) if (updateBilling && !string.IsNullOrWhiteSpace(organization.GatewayCustomerId))
{ {
@ -862,7 +867,7 @@ public class OrganizationService : IOrganizationService
if (newSeatsRequired > 0) if (newSeatsRequired > 0)
{ {
var (canScale, failureReason) = CanScale(organization, newSeatsRequired); var (canScale, failureReason) = await CanScaleAsync(organization, newSeatsRequired);
if (!canScale) if (!canScale)
{ {
throw new BadRequestException(failureReason); throw new BadRequestException(failureReason);
@ -1182,7 +1187,8 @@ public class OrganizationService : IOrganizationService
return result; return result;
} }
internal (bool canScale, string failureReason) CanScale(Organization organization, internal async Task<(bool canScale, string failureReason)> CanScaleAsync(
Organization organization,
int seatsToAdd) int seatsToAdd)
{ {
var failureReason = ""; var failureReason = "";
@ -1197,6 +1203,13 @@ public class OrganizationService : IOrganizationService
return (true, failureReason); return (true, failureReason);
} }
var provider = await _providerRepository.GetByOrganizationIdAsync(organization.Id);
if (provider is { Enabled: true, Type: ProviderType.Reseller })
{
return (false, "Seat limit has been reached. Contact your provider to purchase additional seats.");
}
if (organization.Seats.HasValue && if (organization.Seats.HasValue &&
organization.MaxAutoscaleSeats.HasValue && organization.MaxAutoscaleSeats.HasValue &&
organization.MaxAutoscaleSeats.Value < organization.Seats.Value + seatsToAdd) organization.MaxAutoscaleSeats.Value < organization.Seats.Value + seatsToAdd)
@ -1214,7 +1227,7 @@ public class OrganizationService : IOrganizationService
return; return;
} }
var (canScale, failureMessage) = CanScale(organization, seatsToAdd); var (canScale, failureMessage) = await CanScaleAsync(organization, seatsToAdd);
if (!canScale) if (!canScale)
{ {
throw new BadRequestException(failureMessage); throw new BadRequestException(failureMessage);

View File

@ -1,5 +1,4 @@
using Bit.Core.Models.BitStripe; using Bit.Core.Models.BitStripe;
using Stripe;
namespace Bit.Core.Services; namespace Bit.Core.Services;
@ -17,7 +16,6 @@ public class StripeAdapter : IStripeAdapter
private readonly Stripe.BankAccountService _bankAccountService; private readonly Stripe.BankAccountService _bankAccountService;
private readonly Stripe.PriceService _priceService; private readonly Stripe.PriceService _priceService;
private readonly Stripe.TestHelpers.TestClockService _testClockService; private readonly Stripe.TestHelpers.TestClockService _testClockService;
private readonly Stripe.InvoiceItemService _invoiceItemService;
public StripeAdapter() public StripeAdapter()
{ {
@ -33,7 +31,6 @@ public class StripeAdapter : IStripeAdapter
_bankAccountService = new Stripe.BankAccountService(); _bankAccountService = new Stripe.BankAccountService();
_priceService = new Stripe.PriceService(); _priceService = new Stripe.PriceService();
_testClockService = new Stripe.TestHelpers.TestClockService(); _testClockService = new Stripe.TestHelpers.TestClockService();
_invoiceItemService = new Stripe.InvoiceItemService();
} }
public Task<Stripe.Customer> CustomerCreateAsync(Stripe.CustomerCreateOptions options) public Task<Stripe.Customer> CustomerCreateAsync(Stripe.CustomerCreateOptions options)
@ -82,16 +79,6 @@ public class StripeAdapter : IStripeAdapter
return _invoiceService.UpcomingAsync(options); return _invoiceService.UpcomingAsync(options);
} }
public Task<Stripe.Invoice> InvoiceCreateAsync(Stripe.InvoiceCreateOptions options)
{
return _invoiceService.CreateAsync(options);
}
public Task<Stripe.InvoiceItem> InvoiceItemCreateAsync(Stripe.InvoiceItemCreateOptions options)
{
return _invoiceItemService.CreateAsync(options);
}
public Task<Stripe.Invoice> InvoiceGetAsync(string id, Stripe.InvoiceGetOptions options) public Task<Stripe.Invoice> InvoiceGetAsync(string id, Stripe.InvoiceGetOptions options)
{ {
return _invoiceService.GetAsync(id, options); return _invoiceService.GetAsync(id, options);
@ -116,11 +103,6 @@ public class StripeAdapter : IStripeAdapter
return invoices; return invoices;
} }
public IEnumerable<InvoiceItem> InvoiceItemListAsync(InvoiceItemListOptions options)
{
return _invoiceItemService.ListAutoPaging(options);
}
public Task<Stripe.Invoice> InvoiceUpdateAsync(string id, Stripe.InvoiceUpdateOptions options) public Task<Stripe.Invoice> InvoiceUpdateAsync(string id, Stripe.InvoiceUpdateOptions options)
{ {
return _invoiceService.UpdateAsync(id, options); return _invoiceService.UpdateAsync(id, options);

View File

@ -7,7 +7,6 @@ using Bit.Core.Models.Business;
using Bit.Core.Repositories; using Bit.Core.Repositories;
using Bit.Core.Settings; using Bit.Core.Settings;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Stripe;
using StaticStore = Bit.Core.Models.StaticStore; using StaticStore = Bit.Core.Models.StaticStore;
using TaxRate = Bit.Core.Entities.TaxRate; using TaxRate = Bit.Core.Entities.TaxRate;
@ -751,14 +750,16 @@ public class StripePaymentService : IPaymentService
prorationDate ??= DateTime.UtcNow; prorationDate ??= DateTime.UtcNow;
var collectionMethod = sub.CollectionMethod; var collectionMethod = sub.CollectionMethod;
var daysUntilDue = sub.DaysUntilDue; var daysUntilDue = sub.DaysUntilDue;
var chargeNow = collectionMethod == "charge_automatically";
var updatedItemOptions = subscriptionUpdate.UpgradeItemsOptions(sub); var updatedItemOptions = subscriptionUpdate.UpgradeItemsOptions(sub);
var subUpdateOptions = new Stripe.SubscriptionUpdateOptions var subUpdateOptions = new Stripe.SubscriptionUpdateOptions
{ {
Items = updatedItemOptions, Items = updatedItemOptions,
ProrationBehavior = Constants.CreateProrations, ProrationBehavior = "always_invoice",
DaysUntilDue = daysUntilDue ?? 1, DaysUntilDue = daysUntilDue ?? 1,
CollectionMethod = "send_invoice" CollectionMethod = "send_invoice",
ProrationDate = prorationDate,
}; };
if (!subscriptionUpdate.UpdateNeeded(sub)) if (!subscriptionUpdate.UpdateNeeded(sub))
@ -792,26 +793,34 @@ public class StripePaymentService : IPaymentService
string paymentIntentClientSecret = null; string paymentIntentClientSecret = null;
try try
{ {
var subItemOptions = updatedItemOptions.Select(itemOption =>
new Stripe.InvoiceSubscriptionItemOptions
{
Id = itemOption.Id,
Plan = itemOption.Plan,
Quantity = itemOption.Quantity,
}).ToList();
var reviewInvoiceResponse = await PreviewUpcomingInvoiceAndPayAsync(storableSubscriber, subItemOptions);
paymentIntentClientSecret = reviewInvoiceResponse.PaymentIntentClientSecret;
var subResponse = await _stripeAdapter.SubscriptionUpdateAsync(sub.Id, subUpdateOptions); var subResponse = await _stripeAdapter.SubscriptionUpdateAsync(sub.Id, subUpdateOptions);
var invoice =
await _stripeAdapter.InvoiceGetAsync(subResponse?.LatestInvoiceId, new Stripe.InvoiceGetOptions()); var invoice = await _stripeAdapter.InvoiceGetAsync(subResponse?.LatestInvoiceId, new Stripe.InvoiceGetOptions());
if (invoice == null) if (invoice == null)
{ {
throw new BadRequestException("Unable to locate draft invoice for subscription update."); throw new BadRequestException("Unable to locate draft invoice for subscription update.");
} }
if (invoice.AmountDue > 0 && updatedItemOptions.Any(i => i.Quantity > 0))
{
try
{
if (chargeNow)
{
paymentIntentClientSecret = await PayInvoiceAfterSubscriptionChangeAsync(
storableSubscriber, invoice);
} }
catch (Exception e) else
{
invoice = await _stripeAdapter.InvoiceFinalizeInvoiceAsync(subResponse.LatestInvoiceId, new Stripe.InvoiceFinalizeOptions
{
AutoAdvance = false,
});
await _stripeAdapter.InvoiceSendInvoiceAsync(invoice.Id, new Stripe.InvoiceSendOptions());
paymentIntentClientSecret = null;
}
}
catch
{ {
// Need to revert the subscription // Need to revert the subscription
await _stripeAdapter.SubscriptionUpdateAsync(sub.Id, new Stripe.SubscriptionUpdateOptions await _stripeAdapter.SubscriptionUpdateAsync(sub.Id, new Stripe.SubscriptionUpdateOptions
@ -825,13 +834,21 @@ public class StripePaymentService : IPaymentService
}); });
throw; throw;
} }
}
else if (!invoice.Paid)
{
// Pay invoice with no charge to customer this completes the invoice immediately without waiting the scheduled 1h
invoice = await _stripeAdapter.InvoicePayAsync(subResponse.LatestInvoiceId);
paymentIntentClientSecret = null;
}
}
finally finally
{ {
// Change back the subscription collection method and/or days until due // Change back the subscription collection method and/or days until due
if (collectionMethod != "send_invoice" || daysUntilDue == null) if (collectionMethod != "send_invoice" || daysUntilDue == null)
{ {
await _stripeAdapter.SubscriptionUpdateAsync(sub.Id, await _stripeAdapter.SubscriptionUpdateAsync(sub.Id, new Stripe.SubscriptionUpdateOptions
new Stripe.SubscriptionUpdateOptions
{ {
CollectionMethod = collectionMethod, CollectionMethod = collectionMethod,
DaysUntilDue = daysUntilDue, DaysUntilDue = daysUntilDue,
@ -918,7 +935,6 @@ public class StripePaymentService : IPaymentService
await _stripeAdapter.CustomerDeleteAsync(subscriber.GatewayCustomerId); await _stripeAdapter.CustomerDeleteAsync(subscriber.GatewayCustomerId);
} }
//This method is no-longer is use because we return the dollar threshold feature on invoice will be generated. but we dont want to lose this implementation.
public async Task<string> PayInvoiceAfterSubscriptionChangeAsync(ISubscriber subscriber, Stripe.Invoice invoice) public async Task<string> PayInvoiceAfterSubscriptionChangeAsync(ISubscriber subscriber, Stripe.Invoice invoice)
{ {
var customerOptions = new Stripe.CustomerGetOptions(); var customerOptions = new Stripe.CustomerGetOptions();
@ -1088,310 +1104,6 @@ public class StripePaymentService : IPaymentService
return paymentIntentClientSecret; return paymentIntentClientSecret;
} }
internal async Task<InvoicePreviewResult> PreviewUpcomingInvoiceAndPayAsync(ISubscriber subscriber,
List<Stripe.InvoiceSubscriptionItemOptions> subItemOptions, int prorateThreshold = 50000)
{
var customer = await CheckInAppPurchaseMethod(subscriber);
string paymentIntentClientSecret = null;
var pendingInvoiceItems = GetPendingInvoiceItems(subscriber);
var upcomingPreview = await GetUpcomingInvoiceAsync(subscriber, subItemOptions);
var itemsForInvoice = GetItemsForInvoice(subItemOptions, upcomingPreview, pendingInvoiceItems);
var invoiceAmount = itemsForInvoice?.Sum(i => i.Amount) ?? 0;
var invoiceNow = invoiceAmount >= prorateThreshold;
if (invoiceNow)
{
await ProcessImmediateInvoiceAsync(subscriber, upcomingPreview, invoiceAmount, customer, itemsForInvoice, pendingInvoiceItems, paymentIntentClientSecret);
}
return new InvoicePreviewResult { IsInvoicedNow = invoiceNow, PaymentIntentClientSecret = paymentIntentClientSecret };
}
private async Task<InvoicePreviewResult> ProcessImmediateInvoiceAsync(ISubscriber subscriber, Invoice upcomingPreview, long invoiceAmount,
Customer customer, IEnumerable<InvoiceLineItem> itemsForInvoice, PendingInoviceItems pendingInvoiceItems,
string paymentIntentClientSecret)
{
// Owes more than prorateThreshold on the next invoice.
// Invoice them and pay now instead of waiting until the next billing cycle.
string cardPaymentMethodId = null;
var invoiceAmountDue = upcomingPreview.StartingBalance + invoiceAmount;
cardPaymentMethodId = GetCardPaymentMethodId(invoiceAmountDue, customer, cardPaymentMethodId);
Stripe.Invoice invoice = null;
var createdInvoiceItems = new List<Stripe.InvoiceItem>();
Braintree.Transaction braintreeTransaction = null;
try
{
await CreateInvoiceItemsAsync(subscriber, itemsForInvoice, pendingInvoiceItems, createdInvoiceItems);
invoice = await CreateInvoiceAsync(subscriber, cardPaymentMethodId);
var invoicePayOptions = new Stripe.InvoicePayOptions();
await CreateBrainTreeTransactionRequestAsync(subscriber, invoice, customer, invoicePayOptions,
cardPaymentMethodId, braintreeTransaction);
await InvoicePayAsync(invoicePayOptions, invoice, paymentIntentClientSecret);
}
catch (Exception e)
{
if (braintreeTransaction != null)
{
await _btGateway.Transaction.RefundAsync(braintreeTransaction.Id);
}
if (invoice != null)
{
if (invoice.Status == "paid")
{
// It's apparently paid, so we return without throwing an exception
return new InvoicePreviewResult
{
IsInvoicedNow = false,
PaymentIntentClientSecret = paymentIntentClientSecret
};
}
await RestoreInvoiceItemsAsync(invoice, customer, pendingInvoiceItems.PendingInvoiceItems);
}
else
{
foreach (var ii in createdInvoiceItems)
{
await _stripeAdapter.InvoiceDeleteAsync(ii.Id);
}
}
if (e is Stripe.StripeException strEx &&
(strEx.StripeError?.Message?.Contains("cannot be used because it is not verified") ?? false))
{
throw new GatewayException("Bank account is not yet verified.");
}
throw;
}
return new InvoicePreviewResult
{
IsInvoicedNow = false,
PaymentIntentClientSecret = paymentIntentClientSecret
};
}
private static IEnumerable<InvoiceLineItem> GetItemsForInvoice(List<InvoiceSubscriptionItemOptions> subItemOptions, Invoice upcomingPreview,
PendingInoviceItems pendingInvoiceItems)
{
var itemsForInvoice = upcomingPreview.Lines?.Data?
.Where(i => pendingInvoiceItems.PendingInvoiceItemsDict.ContainsKey(i.Id) ||
(i.Plan.Id == subItemOptions[0]?.Plan && i.Proration));
return itemsForInvoice;
}
private PendingInoviceItems GetPendingInvoiceItems(ISubscriber subscriber)
{
var pendingInvoiceItems = new PendingInoviceItems();
var invoiceItems = _stripeAdapter.InvoiceItemListAsync(new Stripe.InvoiceItemListOptions
{
Customer = subscriber.GatewayCustomerId
}).ToList().Where(i => i.InvoiceId == null);
pendingInvoiceItems.PendingInvoiceItemsDict = invoiceItems.ToDictionary(pii => pii.Id);
return pendingInvoiceItems;
}
private async Task<Customer> CheckInAppPurchaseMethod(ISubscriber subscriber)
{
var customerOptions = GetCustomerPaymentOptions();
var customer = await _stripeAdapter.CustomerGetAsync(subscriber.GatewayCustomerId, customerOptions);
var usingInAppPaymentMethod = customer.Metadata.ContainsKey("appleReceipt");
if (usingInAppPaymentMethod)
{
throw new BadRequestException("Cannot perform this action with in-app purchase payment method. " +
"Contact support.");
}
return customer;
}
private string GetCardPaymentMethodId(long invoiceAmountDue, Customer customer, string cardPaymentMethodId)
{
try
{
if (invoiceAmountDue <= 0 || customer.Metadata.ContainsKey("btCustomerId")) return cardPaymentMethodId;
var hasDefaultCardPaymentMethod = customer.InvoiceSettings?.DefaultPaymentMethod?.Type == "card";
var hasDefaultValidSource = customer.DefaultSource != null &&
(customer.DefaultSource is Stripe.Card ||
customer.DefaultSource is Stripe.BankAccount);
if (hasDefaultCardPaymentMethod || hasDefaultValidSource) return cardPaymentMethodId;
cardPaymentMethodId = GetLatestCardPaymentMethod(customer.Id)?.Id;
if (cardPaymentMethodId == null)
{
throw new BadRequestException("No payment method is available.");
}
}
catch (Exception e)
{
throw new BadRequestException("No payment method is available.");
}
return cardPaymentMethodId;
}
private async Task<Invoice> GetUpcomingInvoiceAsync(ISubscriber subscriber, List<InvoiceSubscriptionItemOptions> subItemOptions)
{
var upcomingPreview = await _stripeAdapter.InvoiceUpcomingAsync(new Stripe.UpcomingInvoiceOptions
{
Customer = subscriber.GatewayCustomerId,
Subscription = subscriber.GatewaySubscriptionId,
SubscriptionItems = subItemOptions
});
return upcomingPreview;
}
private async Task RestoreInvoiceItemsAsync(Invoice invoice, Customer customer, IEnumerable<InvoiceItem> pendingInvoiceItems)
{
invoice = await _stripeAdapter.InvoiceVoidInvoiceAsync(invoice.Id, new Stripe.InvoiceVoidOptions());
if (invoice.StartingBalance != 0)
{
await _stripeAdapter.CustomerUpdateAsync(customer.Id,
new Stripe.CustomerUpdateOptions { Balance = customer.Balance });
}
// Restore invoice items that were brought in
foreach (var item in pendingInvoiceItems)
{
var i = new Stripe.InvoiceItemCreateOptions
{
Currency = item.Currency,
Description = item.Description,
Customer = item.CustomerId,
Subscription = item.SubscriptionId,
Discountable = item.Discountable,
Metadata = item.Metadata,
Quantity = item.Proration ? 1 : item.Quantity,
UnitAmount = item.UnitAmount
};
await _stripeAdapter.InvoiceItemCreateAsync(i);
}
}
private async Task InvoicePayAsync(InvoicePayOptions invoicePayOptions, Invoice invoice, string paymentIntentClientSecret)
{
try
{
await _stripeAdapter.InvoicePayAsync(invoice.Id, invoicePayOptions);
}
catch (Stripe.StripeException e)
{
if (e.HttpStatusCode == System.Net.HttpStatusCode.PaymentRequired &&
e.StripeError?.Code == "invoice_payment_intent_requires_action")
{
// SCA required, get intent client secret
var invoiceGetOptions = new Stripe.InvoiceGetOptions();
invoiceGetOptions.AddExpand("payment_intent");
invoice = await _stripeAdapter.InvoiceGetAsync(invoice.Id, invoiceGetOptions);
paymentIntentClientSecret = invoice?.PaymentIntent?.ClientSecret;
}
else
{
throw new GatewayException("Unable to pay invoice.");
}
}
}
private async Task CreateBrainTreeTransactionRequestAsync(ISubscriber subscriber, Invoice invoice, Customer customer,
InvoicePayOptions invoicePayOptions, string cardPaymentMethodId, Braintree.Transaction braintreeTransaction)
{
if (invoice.AmountDue > 0)
{
if (customer?.Metadata?.ContainsKey("btCustomerId") ?? false)
{
invoicePayOptions.PaidOutOfBand = true;
var btInvoiceAmount = (invoice.AmountDue / 100M);
var transactionResult = await _btGateway.Transaction.SaleAsync(
new Braintree.TransactionRequest
{
Amount = btInvoiceAmount,
CustomerId = customer.Metadata["btCustomerId"],
Options = new Braintree.TransactionOptionsRequest
{
SubmitForSettlement = true,
PayPal = new Braintree.TransactionOptionsPayPalRequest
{
CustomField = $"{subscriber.BraintreeIdField()}:{subscriber.Id}"
}
},
CustomFields = new Dictionary<string, string>
{
[subscriber.BraintreeIdField()] = subscriber.Id.ToString()
}
});
if (!transactionResult.IsSuccess())
{
throw new GatewayException("Failed to charge PayPal customer.");
}
braintreeTransaction = transactionResult.Target;
await _stripeAdapter.InvoiceUpdateAsync(invoice.Id, new Stripe.InvoiceUpdateOptions
{
Metadata = new Dictionary<string, string>
{
["btTransactionId"] = braintreeTransaction.Id,
["btPayPalTransactionId"] =
braintreeTransaction.PayPalDetails.AuthorizationId
}
});
}
else
{
invoicePayOptions.OffSession = true;
invoicePayOptions.PaymentMethod = cardPaymentMethodId;
}
}
}
private async Task<Invoice> CreateInvoiceAsync(ISubscriber subscriber, string cardPaymentMethodId)
{
Invoice invoice;
invoice = await _stripeAdapter.InvoiceCreateAsync(new Stripe.InvoiceCreateOptions
{
CollectionMethod = "send_invoice",
DaysUntilDue = 1,
Customer = subscriber.GatewayCustomerId,
Subscription = subscriber.GatewaySubscriptionId,
DefaultPaymentMethod = cardPaymentMethodId
});
return invoice;
}
private async Task CreateInvoiceItemsAsync(ISubscriber subscriber, IEnumerable<InvoiceLineItem> itemsForInvoice,
PendingInoviceItems pendingInvoiceItems, List<InvoiceItem> createdInvoiceItems)
{
foreach (var invoiceLineItem in itemsForInvoice)
{
if (pendingInvoiceItems.PendingInvoiceItemsDict.ContainsKey(invoiceLineItem.Id))
{
continue;
}
var invoiceItem = await _stripeAdapter.InvoiceItemCreateAsync(new Stripe.InvoiceItemCreateOptions
{
Currency = invoiceLineItem.Currency,
Description = invoiceLineItem.Description,
Customer = subscriber.GatewayCustomerId,
Subscription = invoiceLineItem.Subscription,
Discountable = invoiceLineItem.Discountable,
Amount = invoiceLineItem.Amount
});
createdInvoiceItems.Add(invoiceItem);
}
}
public async Task CancelSubscriptionAsync(ISubscriber subscriber, bool endOfPeriod = false, public async Task CancelSubscriptionAsync(ISubscriber subscriber, bool endOfPeriod = false,
bool skipInAppPurchaseCheck = false) bool skipInAppPurchaseCheck = false)
{ {

View File

@ -1,11 +1,14 @@
using System.Security.Claims; using System.Security.Claims;
using System.Text.Json; using System.Text.Json;
using Bit.Core.AdminConsole.Enums;
using Bit.Core.AdminConsole.Repositories; using Bit.Core.AdminConsole.Repositories;
using Bit.Core.AdminConsole.Services;
using Bit.Core.Auth.Entities; using Bit.Core.Auth.Entities;
using Bit.Core.Auth.Enums; using Bit.Core.Auth.Enums;
using Bit.Core.Auth.Models; using Bit.Core.Auth.Models;
using Bit.Core.Auth.Models.Business.Tokenables; using Bit.Core.Auth.Models.Business.Tokenables;
using Bit.Core.Auth.Repositories; using Bit.Core.Auth.Repositories;
using Bit.Core.Auth.Utilities;
using Bit.Core.Context; using Bit.Core.Context;
using Bit.Core.Entities; using Bit.Core.Entities;
using Bit.Core.Enums; using Bit.Core.Enums;
@ -61,9 +64,8 @@ public class UserService : UserManager<User>, IUserService, IDisposable
private readonly IAcceptOrgUserCommand _acceptOrgUserCommand; private readonly IAcceptOrgUserCommand _acceptOrgUserCommand;
private readonly IProviderUserRepository _providerUserRepository; private readonly IProviderUserRepository _providerUserRepository;
private readonly IStripeSyncService _stripeSyncService; private readonly IStripeSyncService _stripeSyncService;
private readonly IWebAuthnCredentialRepository _webAuthnCredentialRepository;
private readonly IDataProtectorTokenFactory<WebAuthnLoginTokenable> _webAuthnLoginTokenizer;
private readonly IDataProtectorTokenFactory<OrgUserInviteTokenable> _orgUserInviteTokenDataFactory; private readonly IDataProtectorTokenFactory<OrgUserInviteTokenable> _orgUserInviteTokenDataFactory;
private readonly IWebAuthnCredentialRepository _webAuthnCredentialRepository;
public UserService( public UserService(
IUserRepository userRepository, IUserRepository userRepository,
@ -96,8 +98,7 @@ public class UserService : UserManager<User>, IUserService, IDisposable
IProviderUserRepository providerUserRepository, IProviderUserRepository providerUserRepository,
IStripeSyncService stripeSyncService, IStripeSyncService stripeSyncService,
IDataProtectorTokenFactory<OrgUserInviteTokenable> orgUserInviteTokenDataFactory, IDataProtectorTokenFactory<OrgUserInviteTokenable> orgUserInviteTokenDataFactory,
IWebAuthnCredentialRepository webAuthnRepository, IWebAuthnCredentialRepository webAuthnRepository)
IDataProtectorTokenFactory<WebAuthnLoginTokenable> webAuthnLoginTokenizer)
: base( : base(
store, store,
optionsAccessor, optionsAccessor,
@ -136,7 +137,6 @@ public class UserService : UserManager<User>, IUserService, IDisposable
_stripeSyncService = stripeSyncService; _stripeSyncService = stripeSyncService;
_orgUserInviteTokenDataFactory = orgUserInviteTokenDataFactory; _orgUserInviteTokenDataFactory = orgUserInviteTokenDataFactory;
_webAuthnCredentialRepository = webAuthnRepository; _webAuthnCredentialRepository = webAuthnRepository;
_webAuthnLoginTokenizer = webAuthnLoginTokenizer;
} }
public Guid? GetProperUserId(ClaimsPrincipal principal) public Guid? GetProperUserId(ClaimsPrincipal principal)
@ -586,45 +586,33 @@ public class UserService : UserManager<User>, IUserService, IDisposable
return true; return true;
} }
public async Task<AssertionOptions> StartWebAuthnLoginAssertionAsync(User user) public AssertionOptions StartWebAuthnLoginAssertion()
{ {
var provider = user.GetTwoFactorProvider(TwoFactorProviderType.WebAuthn); return _fido2.GetAssertionOptions(Enumerable.Empty<PublicKeyCredentialDescriptor>(), UserVerificationRequirement.Required);
var existingKeys = await _webAuthnCredentialRepository.GetManyByUserIdAsync(user.Id);
var existingCredentials = existingKeys
.Select(k => new PublicKeyCredentialDescriptor(CoreHelpers.Base64UrlDecode(k.CredentialId)))
.ToList();
if (existingCredentials.Count == 0)
{
return null;
} }
// TODO: PRF? public async Task<(User, WebAuthnCredential)> CompleteWebAuthLoginAssertionAsync(AssertionOptions options, AuthenticatorAssertionRawResponse assertionResponse)
var exts = new AuthenticationExtensionsClientInputs
{ {
UserVerificationMethod = true if (!GuidUtilities.TryParseBytes(assertionResponse.Response.UserHandle, out var userId))
}; {
var options = _fido2.GetAssertionOptions(existingCredentials, UserVerificationRequirement.Required, exts); throw new BadRequestException("Invalid credential.");
// TODO: temp save options to user record somehow
return options;
} }
public async Task<string> CompleteWebAuthLoginAssertionAsync(AuthenticatorAssertionRawResponse assertionResponse, User user) var user = await _userRepository.GetByIdAsync(userId);
if (user == null)
{ {
// TODO: Get options from user record somehow, then clear them throw new BadRequestException("Invalid credential.");
var options = AssertionOptions.FromJson(""); }
var userCredentials = await _webAuthnCredentialRepository.GetManyByUserIdAsync(user.Id); var userCredentials = await _webAuthnCredentialRepository.GetManyByUserIdAsync(user.Id);
var assertionId = CoreHelpers.Base64UrlEncode(assertionResponse.Id); var assertedCredentialId = CoreHelpers.Base64UrlEncode(assertionResponse.Id);
var credential = userCredentials.FirstOrDefault(c => c.CredentialId == assertionId); var credential = userCredentials.FirstOrDefault(c => c.CredentialId == assertedCredentialId);
if (credential == null) if (credential == null)
{ {
return null; throw new BadRequestException("Invalid credential.");
} }
// TODO: Callback to ensure credential ID is unique. Do we care? I don't think so. // Always return true, since we've already filtered the credentials after user id
IsUserHandleOwnerOfCredentialIdAsync callback = (args, cancellationToken) => Task.FromResult(true); IsUserHandleOwnerOfCredentialIdAsync callback = (args, cancellationToken) => Task.FromResult(true);
var credentialPublicKey = CoreHelpers.Base64UrlDecode(credential.PublicKey); var credentialPublicKey = CoreHelpers.Base64UrlDecode(credential.PublicKey);
var assertionVerificationResult = await _fido2.MakeAssertionAsync( var assertionVerificationResult = await _fido2.MakeAssertionAsync(
@ -634,15 +622,12 @@ public class UserService : UserManager<User>, IUserService, IDisposable
credential.Counter = (int)assertionVerificationResult.Counter; credential.Counter = (int)assertionVerificationResult.Counter;
await _webAuthnCredentialRepository.ReplaceAsync(credential); await _webAuthnCredentialRepository.ReplaceAsync(credential);
if (assertionVerificationResult.Status == "ok") if (assertionVerificationResult.Status != "ok")
{ {
var token = _webAuthnLoginTokenizer.Protect(new WebAuthnLoginTokenable(user)); throw new BadRequestException("Invalid credential.");
return token;
}
else
{
return null;
} }
return (user, credential);
} }
public async Task SendEmailVerificationAsync(User user) public async Task SendEmailVerificationAsync(User user)

View File

@ -1,8 +1,29 @@
namespace Bit.Core.Tools.Entities; #nullable enable
using Bit.Core.Tools.Models.Business;
namespace Bit.Core.Tools.Entities;
/// <summary>
/// An entity that can be referenced by a <see cref="ReferenceEvent"/>.
/// </summary>
public interface IReferenceable public interface IReferenceable
{ {
/// <summary>
/// Identifies the entity that generated the event.
/// </summary>
Guid Id { get; set; } Guid Id { get; set; }
string ReferenceData { get; set; }
/// <summary>
/// Contextual information included in the event.
/// </summary>
/// <remarks>
/// Do not store secrets in this field.
/// </remarks>
string? ReferenceData { get; set; }
/// <summary>
/// Returns <see langword="true" /> when the entity is a user.
/// Otherwise returns <see langword="false" />.
/// </summary>
bool IsUser(); bool IsUser();
} }

View File

@ -1,29 +1,125 @@
using System.ComponentModel.DataAnnotations; #nullable enable
using System.ComponentModel.DataAnnotations;
using Bit.Core.Entities; using Bit.Core.Entities;
using Bit.Core.Tools.Enums; using Bit.Core.Tools.Enums;
using Bit.Core.Utilities; using Bit.Core.Utilities;
namespace Bit.Core.Tools.Entities; namespace Bit.Core.Tools.Entities;
/// <summary>
/// An end-to-end encrypted secret accessible to arbitrary
/// entities through a fixed URI.
/// </summary>
public class Send : ITableObject<Guid> public class Send : ITableObject<Guid>
{ {
/// <summary>
/// Uniquely identifies this send.
/// </summary>
public Guid Id { get; set; } public Guid Id { get; set; }
/// <summary>
/// Identifies the user that created this send.
/// </summary>
public Guid? UserId { get; set; } public Guid? UserId { get; set; }
/// <summary>
/// Identifies the organization that created this send.
/// </summary>
/// <remarks>
/// Not presently in-use by client applications.
/// </remarks>
public Guid? OrganizationId { get; set; } public Guid? OrganizationId { get; set; }
/// <summary>
/// Describes the data being sent. This field determines how
/// the <see cref="Data"/> field is interpreted.
/// </summary>
public SendType Type { get; set; } public SendType Type { get; set; }
public string Data { get; set; }
public string Key { get; set; } /// <summary>
/// Stores data containing or pointing to the transmitted secret. JSON.
/// </summary>
/// <note>
/// Must be nullable due to several database column configuration.
/// The application and all other databases assume this is not nullable.
/// Tech debt ticket: PM-4128
/// </note>
public string? Data { get; set; }
/// <summary>
/// Stores the data's encryption key. Encrypted.
/// </summary>
/// <note>
/// Must be nullable due to MySql database column configuration.
/// The application and all other databases assume this is not nullable.
/// Tech debt ticket: PM-4128
/// </note>
public string? Key { get; set; }
/// <summary>
/// Password provided by the user. Protected with pbkdf2.
/// </summary>
[MaxLength(300)] [MaxLength(300)]
public string Password { get; set; } public string? Password { get; set; }
/// <summary>
/// The send becomes unavailable to API callers when
/// <see cref="AccessCount"/> &gt;= <see cref="MaxAccessCount"/>.
/// </summary>
public int? MaxAccessCount { get; set; } public int? MaxAccessCount { get; set; }
/// <summary>
/// Number of times the content was accessed.
/// </summary>
/// <remarks>
/// This value is owned by the server. Clients cannot alter it.
/// </remarks>
public int AccessCount { get; set; } public int AccessCount { get; set; }
/// <summary>
/// The date this send was created.
/// </summary>
public DateTime CreationDate { get; internal set; } = DateTime.UtcNow; public DateTime CreationDate { get; internal set; } = DateTime.UtcNow;
/// <summary>
/// The date this send was last modified.
/// </summary>
public DateTime RevisionDate { get; internal set; } = DateTime.UtcNow; public DateTime RevisionDate { get; internal set; } = DateTime.UtcNow;
/// <summary>
/// The date this send becomes unavailable to API callers.
/// </summary>
public DateTime? ExpirationDate { get; set; } public DateTime? ExpirationDate { get; set; }
/// <summary>
/// The date this send will be unconditionally deleted.
/// </summary>
/// <remarks>
/// This is set by server-side when the user doesn't specify a deletion date.
/// </remarks>
public DateTime DeletionDate { get; set; } public DateTime DeletionDate { get; set; }
/// <summary>
/// When this is true the send is not available to API callers,
/// unless they're the creator.
/// </summary>
public bool Disabled { get; set; } public bool Disabled { get; set; }
/// <summary>
/// Whether the creator's email address should be shown to the recipient.
/// </summary>
/// <value>
/// <see langword="false"/> indicates the email may be shown.
/// <see langword="true"/> indicates the email should be hidden.
/// <see langword="null"/> indicates the client doesn't set the field and
/// the email should be hidden.
/// </value>
public bool? HideEmail { get; set; } public bool? HideEmail { get; set; }
/// <summary>
/// Generates the send's <see cref="Id" />
/// </summary>
public void SetNewId() public void SetNewId()
{ {
Id = CoreHelpers.GenerateComb(); Id = CoreHelpers.GenerateComb();

View File

@ -1,4 +1,6 @@
using System.Text.Json.Serialization; #nullable enable
using System.Text.Json.Serialization;
using Bit.Core.Context; using Bit.Core.Context;
using Bit.Core.Enums; using Bit.Core.Enums;
using Bit.Core.Tools.Entities; using Bit.Core.Tools.Entities;
@ -6,10 +8,23 @@ using Bit.Core.Tools.Enums;
namespace Bit.Core.Tools.Models.Business; namespace Bit.Core.Tools.Models.Business;
/// <summary>
/// Product support monitoring.
/// </summary>
/// <remarks>
/// Do not store secrets in this type.
/// </remarks>
public class ReferenceEvent public class ReferenceEvent
{ {
/// <summary>
/// Instantiates a <see cref="ReferenceEvent"/>.
/// </summary>
public ReferenceEvent() { } public ReferenceEvent() { }
/// <inheritdoc cref="ReferenceEvent()" />
/// <param name="type">Monitored event type.</param>
/// <param name="source">Entity that created the event.</param>
/// <param name="currentContext">The conditions in which the event occurred.</param>
public ReferenceEvent(ReferenceEventType type, IReferenceable source, ICurrentContext currentContext) public ReferenceEvent(ReferenceEventType type, IReferenceable source, ICurrentContext currentContext)
{ {
Type = type; Type = type;
@ -26,48 +41,197 @@ public class ReferenceEvent
} }
} }
/// <summary>
/// Monitored event type.
/// </summary>
[JsonConverter(typeof(JsonStringEnumConverter))] [JsonConverter(typeof(JsonStringEnumConverter))]
public ReferenceEventType Type { get; set; } public ReferenceEventType Type { get; set; }
/// <summary>
/// The kind of entity that created the event.
/// </summary>
[JsonConverter(typeof(JsonStringEnumConverter))] [JsonConverter(typeof(JsonStringEnumConverter))]
public ReferenceEventSource Source { get; set; } public ReferenceEventSource Source { get; set; }
/// <inheritdoc cref="IReferenceable.Id"/>
public Guid Id { get; set; } public Guid Id { get; set; }
public string ReferenceData { get; set; } /// <inheritdoc cref="IReferenceable.ReferenceData"/>
public string? ReferenceData { get; set; }
/// <summary>
/// Moment the event occurred.
/// </summary>
public DateTime EventDate { get; set; } = DateTime.UtcNow; public DateTime EventDate { get; set; } = DateTime.UtcNow;
/// <summary>
/// Number of users sent invitations by an organization.
/// </summary>
/// <value>
/// Should contain a value only on <see cref="ReferenceEventType.InvitedUsers"/> events.
/// Otherwise the value should be <see langword="null"/>.
/// </value>
public int? Users { get; set; } public int? Users { get; set; }
/// <summary>
/// Whether or not a subscription was canceled immediately or at the end of the billing period.
/// </summary>
/// <value>
/// <see langword="true"/> when a cancellation occurs immediately.
/// <see langword="false"/> when a cancellation occurs at the end of a customer's billing period.
/// Should contain a value only on <see cref="ReferenceEventType.CancelSubscription"/> events.
/// Otherwise the value should be <see langword="null"/>.
/// </value>
public bool? EndOfPeriod { get; set; } public bool? EndOfPeriod { get; set; }
public string PlanName { get; set; } /// <summary>
/// Branded name of the subscription.
/// </summary>
/// <value>
/// Should contain a value only for subscription management events.
/// Otherwise the value should be <see langword="null"/>.
/// </value>
public string? PlanName { get; set; }
/// <summary>
/// Identifies a subscription.
/// </summary>
/// <value>
/// Should contain a value only for subscription management events.
/// Otherwise the value should be <see langword="null"/>.
/// </value>
public PlanType? PlanType { get; set; } public PlanType? PlanType { get; set; }
public string OldPlanName { get; set; } /// <summary>
/// The branded name of the prior plan.
/// </summary>
/// <value>
/// Should contain a value only on <see cref="ReferenceEventType.UpgradePlan"/> events
/// initiated by organizations.
/// Otherwise the value should be <see langword="null"/>.
/// </value>
public string? OldPlanName { get; set; }
/// <summary>
/// Identifies the prior plan
/// </summary>
/// <value>
/// Should contain a value only on <see cref="ReferenceEventType.UpgradePlan"/> events
/// initiated by organizations.
/// Otherwise the value should be <see langword="null"/>.
/// </value>
public PlanType? OldPlanType { get; set; } public PlanType? OldPlanType { get; set; }
/// <summary>
/// Seat count when a billable action occurs. When adjusting seats, contains
/// the new seat count.
/// </summary>
/// <value>
/// Should contain a value only on <see cref="ReferenceEventType.Rebilled"/>,
/// <see cref="ReferenceEventType.AdjustSeats"/>, <see cref="ReferenceEventType.UpgradePlan"/>,
/// and <see cref="ReferenceEventType.Signup"/> events initiated by organizations.
/// Otherwise the value should be <see langword="null"/>.
/// </value>
public int? Seats { get; set; } public int? Seats { get; set; }
/// <summary>
/// Seat count when a seat adjustment occurs.
/// </summary>
/// <value>
/// Should contain a value only on <see cref="ReferenceEventType.AdjustSeats"/>
/// events initiated by organizations.
/// Otherwise the value should be <see langword="null"/>.
/// </value>
public int? PreviousSeats { get; set; } public int? PreviousSeats { get; set; }
/// <summary>
/// Qty in GB of storage. When adjusting storage, contains the adjusted
/// storage qty. Otherwise contains the total storage quantity.
/// </summary>
/// <value>
/// Should contain a value only on <see cref="ReferenceEventType.Rebilled"/>,
/// <see cref="ReferenceEventType.AdjustStorage"/>, <see cref="ReferenceEventType.UpgradePlan"/>,
/// and <see cref="ReferenceEventType.Signup"/> events.
/// Otherwise the value should be <see langword="null"/>.
/// </value>
public short? Storage { get; set; } public short? Storage { get; set; }
/// <summary>
/// The type of send created or accessed.
/// </summary>
/// <value>
/// Should contain a value only on <see cref="ReferenceEventType.SendAccessed"/>
/// and <see cref="ReferenceEventType.SendCreated"/> events.
/// Otherwise the value should be <see langword="null"/>.
/// </value>
[JsonConverter(typeof(JsonStringEnumConverter))] [JsonConverter(typeof(JsonStringEnumConverter))]
public SendType? SendType { get; set; } public SendType? SendType { get; set; }
/// <summary>
/// Whether the send has private notes.
/// </summary>
/// <value>
/// <see langword="true"/> when the send has private notes, otherwise <see langword="false"/>.
/// Should contain a value only on <see cref="ReferenceEventType.SendAccessed"/>
/// and <see cref="ReferenceEventType.SendCreated"/> events.
/// Otherwise the value should be <see langword="null"/>.
/// </value>
public bool? SendHasNotes { get; set; } public bool? SendHasNotes { get; set; }
/// <summary>
/// The send expires after its access count exceeds this value.
/// </summary>
/// <value>
/// This field only contains a value when the send has a max access count
/// and <see cref="Type"/> is <see cref="ReferenceEventType.SendAccessed"/>
/// or <see cref="ReferenceEventType.SendCreated"/> events.
/// Otherwise, the value should be <see langword="null"/>.
/// </value>
public int? MaxAccessCount { get; set; } public int? MaxAccessCount { get; set; }
/// <summary>
/// Whether the created send has a password.
/// </summary>
/// <value>
/// Should contain a value only on <see cref="ReferenceEventType.SendAccessed"/>
/// and <see cref="ReferenceEventType.SendCreated"/> events.
/// Otherwise the value should be <see langword="null"/>.
/// </value>
public bool? HasPassword { get; set; } public bool? HasPassword { get; set; }
public string EventRaisedByUser { get; set; } /// <summary>
/// The administrator that performed the action.
/// </summary>
/// <value>
/// Should contain a value only on <see cref="ReferenceEventType.OrganizationCreatedByAdmin"/>
/// and <see cref="ReferenceEventType.OrganizationEditedByAdmin"/> events.
/// Otherwise the value should be <see langword="null"/>.
/// </value>
public string? EventRaisedByUser { get; set; }
/// <summary>
/// Whether or not an organization's trial period was started by a sales person.
/// </summary>
/// <value>
/// Should contain a value only on <see cref="ReferenceEventType.OrganizationCreatedByAdmin"/>
/// and <see cref="ReferenceEventType.OrganizationEditedByAdmin"/> events.
/// Otherwise the value should be <see langword="null"/>.
/// </value>
public bool? SalesAssistedTrialStarted { get; set; } public bool? SalesAssistedTrialStarted { get; set; }
public string ClientId { get; set; } /// <summary>
public Version ClientVersion { get; set; } /// The installation id of the application that originated the event.
/// </summary>
/// <value>
/// <see langword="null"/> when the event was not originated by an application.
/// </value>
public string? ClientId { get; set; }
/// <summary>
/// The version of the client application that originated the event.
/// </summary>
/// <value>
/// <see langword="null"/> when the event was not originated by an application.
/// </value>
public Version? ClientVersion { get; set; }
} }

View File

@ -1,15 +1,33 @@
namespace Bit.Core.Tools.Models.Data; #nullable enable
namespace Bit.Core.Tools.Models.Data;
/// <summary>
/// Shared data for a send
/// </summary>
public abstract class SendData public abstract class SendData
{ {
/// <summary>
/// Instantiates a <see cref="SendData"/>.
/// </summary>
public SendData() { } public SendData() { }
public SendData(string name, string notes) /// <inheritdoc cref="SendData()" />
/// <param name="name">User-provided name of the send.</param>
/// <param name="notes">User-provided private notes of the send.</param>
public SendData(string name, string? notes)
{ {
Name = name; Name = name;
Notes = notes; Notes = notes;
} }
public string Name { get; set; } /// <summary>
public string Notes { get; set; } /// User-provided name of the send.
/// </summary>
public string Name { get; set; } = string.Empty;
/// <summary>
/// User-provided private notes of the send.
/// </summary>
public string? Notes { get; set; } = null;
} }

View File

@ -1,22 +1,64 @@
using System.Text.Json.Serialization; #nullable enable
using System.Diagnostics.CodeAnalysis;
using System.Text.Json.Serialization;
using static System.Text.Json.Serialization.JsonNumberHandling;
namespace Bit.Core.Tools.Models.Data; namespace Bit.Core.Tools.Models.Data;
/// <summary>
/// A file secret being sent.
/// </summary>
public class SendFileData : SendData public class SendFileData : SendData
{ {
/// <summary>
/// Instantiates a <see cref="SendFileData"/>.
/// </summary>
public SendFileData() { } public SendFileData() { }
public SendFileData(string name, string notes, string fileName) /// <inheritdoc cref="SendFileData()"/>
/// <param name="name">Attached file name.</param>
/// <param name="notes">User-provided private notes of the send.</param>
/// <param name="fileName">Attached file name.</param>
public SendFileData(string name, string? notes, string fileName)
: base(name, notes) : base(name, notes)
{ {
FileName = fileName; FileName = fileName;
} }
// We serialize Size as a string since JSON (or Javascript) doesn't support full precision for long numbers /// <summary>
[JsonNumberHandling(JsonNumberHandling.WriteAsString | JsonNumberHandling.AllowReadingFromString)] /// Size of the attached file in bytes.
/// </summary>
/// <remarks>
/// Serialized as a string since JSON (or Javascript) doesn't support
/// full precision for long numbers
/// </remarks>
[JsonNumberHandling(WriteAsString | AllowReadingFromString)]
public long Size { get; set; } public long Size { get; set; }
public string Id { get; set; } /// <summary>
public string FileName { get; set; } /// Uniquely identifies an uploaded file.
/// </summary>
/// <value>
/// Should contain <see langword="null" /> only when a file
/// upload is pending. Should never contain null once the
/// file upload completes.
/// </value>
[DisallowNull]
public string? Id { get; set; }
/// <summary>
/// Attached file name.
/// </summary>
/// <value>
/// Should contain a non-empty string once the file upload completes.
/// </value>
public string FileName { get; set; } = string.Empty;
/// <summary>
/// When true the uploaded file's length was confirmed within
/// the expected tolerance and below the maximum supported
/// file size.
/// </summary>
public bool Validated { get; set; } = true; public bool Validated { get; set; } = true;
} }

View File

@ -1,16 +1,42 @@
namespace Bit.Core.Tools.Models.Data; #nullable enable
namespace Bit.Core.Tools.Models.Data;
/// <summary>
/// A text secret being sent.
/// </summary>
public class SendTextData : SendData public class SendTextData : SendData
{ {
/// <summary>
/// Instantiates a <see cref="SendTextData"/>.
/// </summary>
public SendTextData() { } public SendTextData() { }
public SendTextData(string name, string notes, string text, bool hidden) /// <inheritdoc cref="SendTextData()"/>
/// <param name="name">Attached file name.</param>
/// <param name="notes">User-provided private notes of the send.</param>
/// <param name="text">The secret being sent.</param>
/// <param name="hidden">
/// Indicates whether the secret should be concealed when opening the send.
/// </param>
public SendTextData(string name, string? notes, string? text, bool hidden)
: base(name, notes) : base(name, notes)
{ {
Text = text; Text = text;
Hidden = hidden; Hidden = hidden;
} }
public string Text { get; set; } /// <summary>
/// The secret being sent.
/// </summary>
public string? Text { get; set; }
/// <summary>
/// Indicates whether the secret should be concealed when opening the send.
/// </summary>
/// <value>
/// <see langword="true" /> when the secret should be concealed.
/// Otherwise <see langword="false" />.
/// </value>
public bool Hidden { get; set; } public bool Hidden { get; set; }
} }

View File

@ -1,10 +1,36 @@
using Bit.Core.Repositories; #nullable enable
using Bit.Core.Repositories;
using Bit.Core.Tools.Entities; using Bit.Core.Tools.Entities;
namespace Bit.Core.Tools.Repositories; namespace Bit.Core.Tools.Repositories;
/// <summary>
/// Service for saving and loading <see cref="Send"/>s in persistent storage.
/// </summary>
public interface ISendRepository : IRepository<Send, Guid> public interface ISendRepository : IRepository<Send, Guid>
{ {
/// <summary>
/// Loads all <see cref="Send"/>s created by a user.
/// </summary>
/// <param name="userId">
/// Identifies the user.
/// </param>
/// <returns>
/// A task that completes once the <see cref="Send"/>s have been loaded.
/// The task's result contains the loaded <see cref="Send"/>s.
/// </returns>
Task<ICollection<Send>> GetManyByUserIdAsync(Guid userId); Task<ICollection<Send>> GetManyByUserIdAsync(Guid userId);
/// <summary>
/// Loads <see cref="Send"/>s scheduled for deletion.
/// </summary>
/// <param name="deletionDateBefore">
/// Load sends whose <see cref="Send.DeletionDate" /> is &lt; this date.
/// </param>
/// <returns>
/// A task that completes once the <see cref="Send"/>s have been loaded.
/// The task's result contains the loaded <see cref="Send"/>s.
/// </returns>
Task<ICollection<Send>> GetManyByDeletionDateAsync(DateTime deletionDateBefore); Task<ICollection<Send>> GetManyByDeletionDateAsync(DateTime deletionDateBefore);
} }

View File

@ -1,9 +1,11 @@
using System.Text.Json; using System.Text.Json;
using Bit.Core.AdminConsole.Enums;
using Bit.Core.AdminConsole.Models.Data.Organizations.Policies;
using Bit.Core.AdminConsole.Repositories;
using Bit.Core.AdminConsole.Services;
using Bit.Core.Context; using Bit.Core.Context;
using Bit.Core.Entities; using Bit.Core.Entities;
using Bit.Core.Enums;
using Bit.Core.Exceptions; using Bit.Core.Exceptions;
using Bit.Core.Models.Data.Organizations.Policies;
using Bit.Core.Repositories; using Bit.Core.Repositories;
using Bit.Core.Services; using Bit.Core.Services;
using Bit.Core.Settings; using Bit.Core.Settings;

View File

@ -12,6 +12,7 @@ public class CipherLoginFido2CredentialData
public string RpId { get; set; } public string RpId { get; set; }
public string RpName { get; set; } public string RpName { get; set; }
public string UserHandle { get; set; } public string UserHandle { get; set; }
public string UserName { get; set; }
public string UserDisplayName { get; set; } public string UserDisplayName { get; set; }
public string Counter { get; set; } public string Counter { get; set; }
public string Discoverable { get; set; } public string Discoverable { get; set; }

View File

@ -32,7 +32,7 @@ public interface ICipherRepository : IRepository<Cipher, Guid>
Task UpdateCiphersAsync(Guid userId, IEnumerable<Cipher> ciphers); Task UpdateCiphersAsync(Guid userId, IEnumerable<Cipher> ciphers);
Task CreateAsync(IEnumerable<Cipher> ciphers, IEnumerable<Folder> folders); Task CreateAsync(IEnumerable<Cipher> ciphers, IEnumerable<Folder> folders);
Task CreateAsync(IEnumerable<Cipher> ciphers, IEnumerable<Collection> collections, Task CreateAsync(IEnumerable<Cipher> ciphers, IEnumerable<Collection> collections,
IEnumerable<CollectionCipher> collectionCiphers); IEnumerable<CollectionCipher> collectionCiphers, IEnumerable<CollectionUser> collectionUsers);
Task SoftDeleteAsync(IEnumerable<Guid> ids, Guid userId); Task SoftDeleteAsync(IEnumerable<Guid> ids, Guid userId);
Task SoftDeleteByIdsOrganizationIdAsync(IEnumerable<Guid> ids, Guid organizationId); Task SoftDeleteByIdsOrganizationIdAsync(IEnumerable<Guid> ids, Guid organizationId);
Task<DateTime> RestoreAsync(IEnumerable<Guid> ids, Guid userId); Task<DateTime> RestoreAsync(IEnumerable<Guid> ids, Guid userId);

View File

@ -1,4 +1,6 @@
using System.Text.Json; using System.Text.Json;
using Bit.Core.AdminConsole.Enums;
using Bit.Core.AdminConsole.Services;
using Bit.Core.Context; using Bit.Core.Context;
using Bit.Core.Entities; using Bit.Core.Entities;
using Bit.Core.Enums; using Bit.Core.Enums;
@ -25,6 +27,7 @@ public class CipherService : ICipherService
private readonly ICollectionRepository _collectionRepository; private readonly ICollectionRepository _collectionRepository;
private readonly IUserRepository _userRepository; private readonly IUserRepository _userRepository;
private readonly IOrganizationRepository _organizationRepository; private readonly IOrganizationRepository _organizationRepository;
private readonly IOrganizationUserRepository _organizationUserRepository;
private readonly ICollectionCipherRepository _collectionCipherRepository; private readonly ICollectionCipherRepository _collectionCipherRepository;
private readonly IPushNotificationService _pushService; private readonly IPushNotificationService _pushService;
private readonly IAttachmentStorageService _attachmentStorageService; private readonly IAttachmentStorageService _attachmentStorageService;
@ -42,6 +45,7 @@ public class CipherService : ICipherService
ICollectionRepository collectionRepository, ICollectionRepository collectionRepository,
IUserRepository userRepository, IUserRepository userRepository,
IOrganizationRepository organizationRepository, IOrganizationRepository organizationRepository,
IOrganizationUserRepository organizationUserRepository,
ICollectionCipherRepository collectionCipherRepository, ICollectionCipherRepository collectionCipherRepository,
IPushNotificationService pushService, IPushNotificationService pushService,
IAttachmentStorageService attachmentStorageService, IAttachmentStorageService attachmentStorageService,
@ -57,6 +61,7 @@ public class CipherService : ICipherService
_collectionRepository = collectionRepository; _collectionRepository = collectionRepository;
_userRepository = userRepository; _userRepository = userRepository;
_organizationRepository = organizationRepository; _organizationRepository = organizationRepository;
_organizationUserRepository = organizationUserRepository;
_collectionCipherRepository = collectionCipherRepository; _collectionCipherRepository = collectionCipherRepository;
_pushService = pushService; _pushService = pushService;
_attachmentStorageService = attachmentStorageService; _attachmentStorageService = attachmentStorageService;
@ -745,6 +750,7 @@ public class CipherService : ICipherService
var org = collections.Count > 0 ? var org = collections.Count > 0 ?
await _organizationRepository.GetByIdAsync(collections[0].OrganizationId) : await _organizationRepository.GetByIdAsync(collections[0].OrganizationId) :
await _organizationRepository.GetByIdAsync(ciphers.FirstOrDefault(c => c.OrganizationId.HasValue).OrganizationId.Value); await _organizationRepository.GetByIdAsync(ciphers.FirstOrDefault(c => c.OrganizationId.HasValue).OrganizationId.Value);
var importingOrgUser = await _organizationUserRepository.GetByOrganizationAsync(org.Id, importingUserId);
if (collections.Count > 0 && org != null && org.MaxCollections.HasValue) if (collections.Count > 0 && org != null && org.MaxCollections.HasValue)
{ {
@ -762,18 +768,25 @@ public class CipherService : ICipherService
cipher.SetNewId(); cipher.SetNewId();
} }
var userCollectionsIds = (await _collectionRepository.GetManyByOrganizationIdAsync(org.Id)).Select(c => c.Id).ToList(); var organizationCollectionsIds = (await _collectionRepository.GetManyByOrganizationIdAsync(org.Id)).Select(c => c.Id).ToList();
//Assign id to the ones that don't exist in DB //Assign id to the ones that don't exist in DB
//Need to keep the list order to create the relationships //Need to keep the list order to create the relationships
List<Collection> newCollections = new List<Collection>(); var newCollections = new List<Collection>();
var newCollectionUsers = new List<CollectionUser>();
foreach (var collection in collections) foreach (var collection in collections)
{ {
if (!userCollectionsIds.Contains(collection.Id)) if (!organizationCollectionsIds.Contains(collection.Id))
{ {
collection.SetNewId(); collection.SetNewId();
newCollections.Add(collection); newCollections.Add(collection);
newCollectionUsers.Add(new CollectionUser
{
CollectionId = collection.Id,
OrganizationUserId = importingOrgUser.Id,
Manage = true
});
} }
} }
@ -797,7 +810,7 @@ public class CipherService : ICipherService
} }
// Create it all // Create it all
await _cipherRepository.CreateAsync(ciphers, newCollections, collectionCiphers); await _cipherRepository.CreateAsync(ciphers, newCollections, collectionCiphers, newCollectionUsers);
// push // push
await _pushService.PushSyncVaultAsync(importingUserId); await _pushService.PushSyncVaultAsync(importingUserId);

View File

@ -131,6 +131,16 @@
"Microsoft.Win32.Registry": "5.0.0" "Microsoft.Win32.Registry": "5.0.0"
} }
}, },
"Duende.IdentityServer": {
"type": "Direct",
"requested": "[6.0.4, )",
"resolved": "6.0.4",
"contentHash": "4HVjzx1F8v5J+U7oa8RGAQGj2QzmzNSu87r18Sh+dlh10uyZZL8teAaT/FaVLDObnfItGdPFvN8mwpF/HkI3Xw==",
"dependencies": {
"Duende.IdentityServer.Storage": "6.0.4",
"Microsoft.AspNetCore.Authentication.OpenIdConnect": "6.0.0"
}
},
"Fido2.AspNet": { "Fido2.AspNet": {
"type": "Direct", "type": "Direct",
"requested": "[3.0.1, )", "requested": "[3.0.1, )",
@ -150,29 +160,6 @@
"Microsoft.CSharp": "4.7.0" "Microsoft.CSharp": "4.7.0"
} }
}, },
"IdentityServer4": {
"type": "Direct",
"requested": "[4.1.2, )",
"resolved": "4.1.2",
"contentHash": "blaxxGuOA7v/w1q+fxn97wZ+x2ecG1ZD4mc/N/ZOXMNeFZZhqv+4LF26Gecyik3nWrJPmbMEtQbLmRsKG8k61w==",
"dependencies": {
"IdentityModel": "4.4.0",
"IdentityServer4.Storage": "4.1.2",
"Microsoft.AspNetCore.Authentication.OpenIdConnect": "3.1.0",
"Microsoft.IdentityModel.Protocols.OpenIdConnect": "5.6.0",
"Newtonsoft.Json": "12.0.2"
}
},
"IdentityServer4.AccessTokenValidation": {
"type": "Direct",
"requested": "[3.0.1, )",
"resolved": "3.0.1",
"contentHash": "qu/M6UyN4o9NVep7q545Ms7hYAnsQqSdLbN1Fjjrn4m35lyBfeQPSSNzDryAKHbodyWOQfHaOqKEyMEJQ5Rpgw==",
"dependencies": {
"IdentityModel.AspNetCore.OAuth2Introspection": "4.0.1",
"Microsoft.AspNetCore.Authentication.JwtBearer": "3.0.0"
}
},
"LaunchDarkly.ServerSdk": { "LaunchDarkly.ServerSdk": {
"type": "Direct", "type": "Direct",
"requested": "[8.0.0, )", "requested": "[8.0.0, )",
@ -465,6 +452,15 @@
"resolved": "2.2.1", "resolved": "2.2.1",
"contentHash": "A6Zr52zVqJKt18ZBsTnX0qhG0kwIQftVAjLmszmkiR/trSp8H+xj1gUOzk7XHwaKgyREMSV1v9XaKrBUeIOdvQ==" "contentHash": "A6Zr52zVqJKt18ZBsTnX0qhG0kwIQftVAjLmszmkiR/trSp8H+xj1gUOzk7XHwaKgyREMSV1v9XaKrBUeIOdvQ=="
}, },
"Duende.IdentityServer.Storage": {
"type": "Transitive",
"resolved": "6.0.4",
"contentHash": "s5gAjfbpr2IMgI+fU2Nx+2AZdzstmbt9gpo13iX7GwvqSeSaBVqj9ZskAN0R2KF1OemPdZuGnfaTcevdXMUrrw==",
"dependencies": {
"IdentityModel": "6.0.0",
"Microsoft.AspNetCore.DataProtection.Abstractions": "6.0.0"
}
},
"Fido2": { "Fido2": {
"type": "Transitive", "type": "Transitive",
"resolved": "3.0.1", "resolved": "3.0.1",
@ -484,28 +480,8 @@
}, },
"IdentityModel": { "IdentityModel": {
"type": "Transitive", "type": "Transitive",
"resolved": "4.4.0", "resolved": "6.0.0",
"contentHash": "b18wrIx5wnZlMxAX7oVsE+nDtAJ4hajYlH0xPlaRvo4r/fz08K6pPeZvbiqS9nfNbzfIgLFmNX+FL9qR9ZR5PA==", "contentHash": "eVHCR7a6m/dm5RFcBzE3qs/Jg5j9R5Rjpu8aTOv9e4AFvaQtBXb5ah7kmwU+YwA0ufRwz4wf1hnIvsD2hSnI4g=="
"dependencies": {
"Newtonsoft.Json": "11.0.2",
"System.Text.Encodings.Web": "4.7.0"
}
},
"IdentityModel.AspNetCore.OAuth2Introspection": {
"type": "Transitive",
"resolved": "4.0.1",
"contentHash": "ZNdMZMaj9fqR3j50vYsu+1U3QGd6n8+fqwf+a8mCTcmXGor+HgFDfdq0mM34bsmD6uEgAQup7sv2ZW5kR36dbA==",
"dependencies": {
"IdentityModel": "4.0.0"
}
},
"IdentityServer4.Storage": {
"type": "Transitive",
"resolved": "4.1.2",
"contentHash": "KoSffyZyyeCNTIyJiZnCuPakJ1QbCHlpty6gbWUj/7yl+w0PXIchgmmJnJSvddzBb8iZ2xew/vGlxWUIP17P2g==",
"dependencies": {
"IdentityModel": "4.4.0"
}
}, },
"LaunchDarkly.Cache": { "LaunchDarkly.Cache": {
"type": "Transitive", "type": "Transitive",
@ -554,10 +530,10 @@
}, },
"Microsoft.AspNetCore.Authentication.OpenIdConnect": { "Microsoft.AspNetCore.Authentication.OpenIdConnect": {
"type": "Transitive", "type": "Transitive",
"resolved": "3.1.0", "resolved": "6.0.0",
"contentHash": "O1cAQYUTU8EfRqwc5/rfTns4E4hKlFlg59fuKRrST+PzsxI6H07KqRN/JjdYhAuVYxF8jPnIGbj+zuc5paOWUw==", "contentHash": "cJxdro36spFzk/K2OFCddM6vZ+yoj6ug8mTFRH3Gdv1Pul/buSuCtfb/FSCp31UmS5S4C1315dU7wX3ErLFuDg==",
"dependencies": { "dependencies": {
"Microsoft.IdentityModel.Protocols.OpenIdConnect": "5.5.0" "Microsoft.IdentityModel.Protocols.OpenIdConnect": "6.10.0"
} }
}, },
"Microsoft.AspNetCore.Cryptography.Internal": { "Microsoft.AspNetCore.Cryptography.Internal": {
@ -590,8 +566,8 @@
}, },
"Microsoft.AspNetCore.DataProtection.Abstractions": { "Microsoft.AspNetCore.DataProtection.Abstractions": {
"type": "Transitive", "type": "Transitive",
"resolved": "3.1.32", "resolved": "6.0.0",
"contentHash": "MPL4iVyiaRxnOUY5VATHjvhDWaAEFb77KFiUxVRklv3Z3v+STofUr1UG/aCt1O9cgN7FVTDaC5A7U+zsLub8Xg==" "contentHash": "Z/UU4NEBm5UgNufJmw+j5baW26ytCOIZ0G7sZocPaOzsUeBon1bkM3lSMNZQG2GmDjAIVP2XMSODf2jzSGbibw=="
}, },
"Microsoft.Azure.Amqp": { "Microsoft.Azure.Amqp": {
"type": "Transitive", "type": "Transitive",

View File

@ -16,8 +16,8 @@ public class Program
logging.AddSerilog(hostingContext, (e, globalSettings) => logging.AddSerilog(hostingContext, (e, globalSettings) =>
{ {
var context = e.Properties["SourceContext"].ToString(); var context = e.Properties["SourceContext"].ToString();
if (context.Contains("IdentityServer4.Validation.TokenValidator") || if (context.Contains("Duende.IdentityServer.Validation.TokenValidator") ||
context.Contains("IdentityServer4.Validation.TokenRequestValidator")) context.Contains("Duende.IdentityServer.Validation.TokenRequestValidator"))
{ {
return e.Level >= globalSettings.MinLogLevel.EventsSettings.IdentityToken; return e.Level >= globalSettings.MinLogLevel.EventsSettings.IdentityToken;
} }

View File

@ -184,6 +184,24 @@
"Microsoft.Win32.Registry": "5.0.0" "Microsoft.Win32.Registry": "5.0.0"
} }
}, },
"Duende.IdentityServer": {
"type": "Transitive",
"resolved": "6.0.4",
"contentHash": "4HVjzx1F8v5J+U7oa8RGAQGj2QzmzNSu87r18Sh+dlh10uyZZL8teAaT/FaVLDObnfItGdPFvN8mwpF/HkI3Xw==",
"dependencies": {
"Duende.IdentityServer.Storage": "6.0.4",
"Microsoft.AspNetCore.Authentication.OpenIdConnect": "6.0.0"
}
},
"Duende.IdentityServer.Storage": {
"type": "Transitive",
"resolved": "6.0.4",
"contentHash": "s5gAjfbpr2IMgI+fU2Nx+2AZdzstmbt9gpo13iX7GwvqSeSaBVqj9ZskAN0R2KF1OemPdZuGnfaTcevdXMUrrw==",
"dependencies": {
"IdentityModel": "6.0.0",
"Microsoft.AspNetCore.DataProtection.Abstractions": "6.0.0"
}
},
"Fido2": { "Fido2": {
"type": "Transitive", "type": "Transitive",
"resolved": "3.0.1", "resolved": "3.0.1",
@ -220,49 +238,8 @@
}, },
"IdentityModel": { "IdentityModel": {
"type": "Transitive", "type": "Transitive",
"resolved": "4.4.0", "resolved": "6.0.0",
"contentHash": "b18wrIx5wnZlMxAX7oVsE+nDtAJ4hajYlH0xPlaRvo4r/fz08K6pPeZvbiqS9nfNbzfIgLFmNX+FL9qR9ZR5PA==", "contentHash": "eVHCR7a6m/dm5RFcBzE3qs/Jg5j9R5Rjpu8aTOv9e4AFvaQtBXb5ah7kmwU+YwA0ufRwz4wf1hnIvsD2hSnI4g=="
"dependencies": {
"Newtonsoft.Json": "11.0.2",
"System.Text.Encodings.Web": "4.7.0"
}
},
"IdentityModel.AspNetCore.OAuth2Introspection": {
"type": "Transitive",
"resolved": "4.0.1",
"contentHash": "ZNdMZMaj9fqR3j50vYsu+1U3QGd6n8+fqwf+a8mCTcmXGor+HgFDfdq0mM34bsmD6uEgAQup7sv2ZW5kR36dbA==",
"dependencies": {
"IdentityModel": "4.0.0"
}
},
"IdentityServer4": {
"type": "Transitive",
"resolved": "4.1.2",
"contentHash": "blaxxGuOA7v/w1q+fxn97wZ+x2ecG1ZD4mc/N/ZOXMNeFZZhqv+4LF26Gecyik3nWrJPmbMEtQbLmRsKG8k61w==",
"dependencies": {
"IdentityModel": "4.4.0",
"IdentityServer4.Storage": "4.1.2",
"Microsoft.AspNetCore.Authentication.OpenIdConnect": "3.1.0",
"Microsoft.IdentityModel.Protocols.OpenIdConnect": "5.6.0",
"Newtonsoft.Json": "12.0.2"
}
},
"IdentityServer4.AccessTokenValidation": {
"type": "Transitive",
"resolved": "3.0.1",
"contentHash": "qu/M6UyN4o9NVep7q545Ms7hYAnsQqSdLbN1Fjjrn4m35lyBfeQPSSNzDryAKHbodyWOQfHaOqKEyMEJQ5Rpgw==",
"dependencies": {
"IdentityModel.AspNetCore.OAuth2Introspection": "4.0.1",
"Microsoft.AspNetCore.Authentication.JwtBearer": "3.0.0"
}
},
"IdentityServer4.Storage": {
"type": "Transitive",
"resolved": "4.1.2",
"contentHash": "KoSffyZyyeCNTIyJiZnCuPakJ1QbCHlpty6gbWUj/7yl+w0PXIchgmmJnJSvddzBb8iZ2xew/vGlxWUIP17P2g==",
"dependencies": {
"IdentityModel": "4.4.0"
}
}, },
"LaunchDarkly.Cache": { "LaunchDarkly.Cache": {
"type": "Transitive", "type": "Transitive",
@ -354,10 +331,10 @@
}, },
"Microsoft.AspNetCore.Authentication.OpenIdConnect": { "Microsoft.AspNetCore.Authentication.OpenIdConnect": {
"type": "Transitive", "type": "Transitive",
"resolved": "3.1.0", "resolved": "6.0.0",
"contentHash": "O1cAQYUTU8EfRqwc5/rfTns4E4hKlFlg59fuKRrST+PzsxI6H07KqRN/JjdYhAuVYxF8jPnIGbj+zuc5paOWUw==", "contentHash": "cJxdro36spFzk/K2OFCddM6vZ+yoj6ug8mTFRH3Gdv1Pul/buSuCtfb/FSCp31UmS5S4C1315dU7wX3ErLFuDg==",
"dependencies": { "dependencies": {
"Microsoft.IdentityModel.Protocols.OpenIdConnect": "5.5.0" "Microsoft.IdentityModel.Protocols.OpenIdConnect": "6.10.0"
} }
}, },
"Microsoft.AspNetCore.Cryptography.Internal": { "Microsoft.AspNetCore.Cryptography.Internal": {
@ -390,8 +367,8 @@
}, },
"Microsoft.AspNetCore.DataProtection.Abstractions": { "Microsoft.AspNetCore.DataProtection.Abstractions": {
"type": "Transitive", "type": "Transitive",
"resolved": "3.1.32", "resolved": "6.0.0",
"contentHash": "MPL4iVyiaRxnOUY5VATHjvhDWaAEFb77KFiUxVRklv3Z3v+STofUr1UG/aCt1O9cgN7FVTDaC5A7U+zsLub8Xg==" "contentHash": "Z/UU4NEBm5UgNufJmw+j5baW26ytCOIZ0G7sZocPaOzsUeBon1bkM3lSMNZQG2GmDjAIVP2XMSODf2jzSGbibw=="
}, },
"Microsoft.Azure.Amqp": { "Microsoft.Azure.Amqp": {
"type": "Transitive", "type": "Transitive",
@ -2617,10 +2594,9 @@
"BitPay.Light": "[1.0.1907, )", "BitPay.Light": "[1.0.1907, )",
"Braintree": "[5.19.0, )", "Braintree": "[5.19.0, )",
"DnsClient": "[1.7.0, )", "DnsClient": "[1.7.0, )",
"Duende.IdentityServer": "[6.0.4, )",
"Fido2.AspNet": "[3.0.1, )", "Fido2.AspNet": "[3.0.1, )",
"Handlebars.Net": "[2.1.2, )", "Handlebars.Net": "[2.1.2, )",
"IdentityServer4": "[4.1.2, )",
"IdentityServer4.AccessTokenValidation": "[3.0.1, )",
"LaunchDarkly.ServerSdk": "[8.0.0, )", "LaunchDarkly.ServerSdk": "[8.0.0, )",
"MailKit": "[4.2.0, )", "MailKit": "[4.2.0, )",
"Microsoft.AspNetCore.Authentication.JwtBearer": "[6.0.4, )", "Microsoft.AspNetCore.Authentication.JwtBearer": "[6.0.4, )",
@ -2648,7 +2624,7 @@
"infrastructure.dapper": { "infrastructure.dapper": {
"type": "Project", "type": "Project",
"dependencies": { "dependencies": {
"Core": "[2023.10.2, )", "Core": "[2023.10.3, )",
"Dapper": "[2.0.123, )" "Dapper": "[2.0.123, )"
} }
}, },
@ -2656,7 +2632,7 @@
"type": "Project", "type": "Project",
"dependencies": { "dependencies": {
"AutoMapper.Extensions.Microsoft.DependencyInjection": "[12.0.1, )", "AutoMapper.Extensions.Microsoft.DependencyInjection": "[12.0.1, )",
"Core": "[2023.10.2, )", "Core": "[2023.10.3, )",
"Microsoft.EntityFrameworkCore.Relational": "[7.0.5, )", "Microsoft.EntityFrameworkCore.Relational": "[7.0.5, )",
"Microsoft.EntityFrameworkCore.SqlServer": "[7.0.5, )", "Microsoft.EntityFrameworkCore.SqlServer": "[7.0.5, )",
"Microsoft.EntityFrameworkCore.Sqlite": "[7.0.5, )", "Microsoft.EntityFrameworkCore.Sqlite": "[7.0.5, )",
@ -2668,9 +2644,9 @@
"sharedweb": { "sharedweb": {
"type": "Project", "type": "Project",
"dependencies": { "dependencies": {
"Core": "[2023.10.2, )", "Core": "[2023.10.3, )",
"Infrastructure.Dapper": "[2023.10.2, )", "Infrastructure.Dapper": "[2023.10.3, )",
"Infrastructure.EntityFramework": "[2023.10.2, )" "Infrastructure.EntityFramework": "[2023.10.3, )"
} }
} }
} }

View File

@ -184,6 +184,24 @@
"Microsoft.Win32.Registry": "5.0.0" "Microsoft.Win32.Registry": "5.0.0"
} }
}, },
"Duende.IdentityServer": {
"type": "Transitive",
"resolved": "6.0.4",
"contentHash": "4HVjzx1F8v5J+U7oa8RGAQGj2QzmzNSu87r18Sh+dlh10uyZZL8teAaT/FaVLDObnfItGdPFvN8mwpF/HkI3Xw==",
"dependencies": {
"Duende.IdentityServer.Storage": "6.0.4",
"Microsoft.AspNetCore.Authentication.OpenIdConnect": "6.0.0"
}
},
"Duende.IdentityServer.Storage": {
"type": "Transitive",
"resolved": "6.0.4",
"contentHash": "s5gAjfbpr2IMgI+fU2Nx+2AZdzstmbt9gpo13iX7GwvqSeSaBVqj9ZskAN0R2KF1OemPdZuGnfaTcevdXMUrrw==",
"dependencies": {
"IdentityModel": "6.0.0",
"Microsoft.AspNetCore.DataProtection.Abstractions": "6.0.0"
}
},
"Fido2": { "Fido2": {
"type": "Transitive", "type": "Transitive",
"resolved": "3.0.1", "resolved": "3.0.1",
@ -220,49 +238,8 @@
}, },
"IdentityModel": { "IdentityModel": {
"type": "Transitive", "type": "Transitive",
"resolved": "4.4.0", "resolved": "6.0.0",
"contentHash": "b18wrIx5wnZlMxAX7oVsE+nDtAJ4hajYlH0xPlaRvo4r/fz08K6pPeZvbiqS9nfNbzfIgLFmNX+FL9qR9ZR5PA==", "contentHash": "eVHCR7a6m/dm5RFcBzE3qs/Jg5j9R5Rjpu8aTOv9e4AFvaQtBXb5ah7kmwU+YwA0ufRwz4wf1hnIvsD2hSnI4g=="
"dependencies": {
"Newtonsoft.Json": "11.0.2",
"System.Text.Encodings.Web": "4.7.0"
}
},
"IdentityModel.AspNetCore.OAuth2Introspection": {
"type": "Transitive",
"resolved": "4.0.1",
"contentHash": "ZNdMZMaj9fqR3j50vYsu+1U3QGd6n8+fqwf+a8mCTcmXGor+HgFDfdq0mM34bsmD6uEgAQup7sv2ZW5kR36dbA==",
"dependencies": {
"IdentityModel": "4.0.0"
}
},
"IdentityServer4": {
"type": "Transitive",
"resolved": "4.1.2",
"contentHash": "blaxxGuOA7v/w1q+fxn97wZ+x2ecG1ZD4mc/N/ZOXMNeFZZhqv+4LF26Gecyik3nWrJPmbMEtQbLmRsKG8k61w==",
"dependencies": {
"IdentityModel": "4.4.0",
"IdentityServer4.Storage": "4.1.2",
"Microsoft.AspNetCore.Authentication.OpenIdConnect": "3.1.0",
"Microsoft.IdentityModel.Protocols.OpenIdConnect": "5.6.0",
"Newtonsoft.Json": "12.0.2"
}
},
"IdentityServer4.AccessTokenValidation": {
"type": "Transitive",
"resolved": "3.0.1",
"contentHash": "qu/M6UyN4o9NVep7q545Ms7hYAnsQqSdLbN1Fjjrn4m35lyBfeQPSSNzDryAKHbodyWOQfHaOqKEyMEJQ5Rpgw==",
"dependencies": {
"IdentityModel.AspNetCore.OAuth2Introspection": "4.0.1",
"Microsoft.AspNetCore.Authentication.JwtBearer": "3.0.0"
}
},
"IdentityServer4.Storage": {
"type": "Transitive",
"resolved": "4.1.2",
"contentHash": "KoSffyZyyeCNTIyJiZnCuPakJ1QbCHlpty6gbWUj/7yl+w0PXIchgmmJnJSvddzBb8iZ2xew/vGlxWUIP17P2g==",
"dependencies": {
"IdentityModel": "4.4.0"
}
}, },
"LaunchDarkly.Cache": { "LaunchDarkly.Cache": {
"type": "Transitive", "type": "Transitive",
@ -354,10 +331,10 @@
}, },
"Microsoft.AspNetCore.Authentication.OpenIdConnect": { "Microsoft.AspNetCore.Authentication.OpenIdConnect": {
"type": "Transitive", "type": "Transitive",
"resolved": "3.1.0", "resolved": "6.0.0",
"contentHash": "O1cAQYUTU8EfRqwc5/rfTns4E4hKlFlg59fuKRrST+PzsxI6H07KqRN/JjdYhAuVYxF8jPnIGbj+zuc5paOWUw==", "contentHash": "cJxdro36spFzk/K2OFCddM6vZ+yoj6ug8mTFRH3Gdv1Pul/buSuCtfb/FSCp31UmS5S4C1315dU7wX3ErLFuDg==",
"dependencies": { "dependencies": {
"Microsoft.IdentityModel.Protocols.OpenIdConnect": "5.5.0" "Microsoft.IdentityModel.Protocols.OpenIdConnect": "6.10.0"
} }
}, },
"Microsoft.AspNetCore.Cryptography.Internal": { "Microsoft.AspNetCore.Cryptography.Internal": {
@ -390,8 +367,8 @@
}, },
"Microsoft.AspNetCore.DataProtection.Abstractions": { "Microsoft.AspNetCore.DataProtection.Abstractions": {
"type": "Transitive", "type": "Transitive",
"resolved": "3.1.32", "resolved": "6.0.0",
"contentHash": "MPL4iVyiaRxnOUY5VATHjvhDWaAEFb77KFiUxVRklv3Z3v+STofUr1UG/aCt1O9cgN7FVTDaC5A7U+zsLub8Xg==" "contentHash": "Z/UU4NEBm5UgNufJmw+j5baW26ytCOIZ0G7sZocPaOzsUeBon1bkM3lSMNZQG2GmDjAIVP2XMSODf2jzSGbibw=="
}, },
"Microsoft.Azure.Amqp": { "Microsoft.Azure.Amqp": {
"type": "Transitive", "type": "Transitive",
@ -2617,10 +2594,9 @@
"BitPay.Light": "[1.0.1907, )", "BitPay.Light": "[1.0.1907, )",
"Braintree": "[5.19.0, )", "Braintree": "[5.19.0, )",
"DnsClient": "[1.7.0, )", "DnsClient": "[1.7.0, )",
"Duende.IdentityServer": "[6.0.4, )",
"Fido2.AspNet": "[3.0.1, )", "Fido2.AspNet": "[3.0.1, )",
"Handlebars.Net": "[2.1.2, )", "Handlebars.Net": "[2.1.2, )",
"IdentityServer4": "[4.1.2, )",
"IdentityServer4.AccessTokenValidation": "[3.0.1, )",
"LaunchDarkly.ServerSdk": "[8.0.0, )", "LaunchDarkly.ServerSdk": "[8.0.0, )",
"MailKit": "[4.2.0, )", "MailKit": "[4.2.0, )",
"Microsoft.AspNetCore.Authentication.JwtBearer": "[6.0.4, )", "Microsoft.AspNetCore.Authentication.JwtBearer": "[6.0.4, )",
@ -2648,7 +2624,7 @@
"infrastructure.dapper": { "infrastructure.dapper": {
"type": "Project", "type": "Project",
"dependencies": { "dependencies": {
"Core": "[2023.10.2, )", "Core": "[2023.10.3, )",
"Dapper": "[2.0.123, )" "Dapper": "[2.0.123, )"
} }
}, },
@ -2656,7 +2632,7 @@
"type": "Project", "type": "Project",
"dependencies": { "dependencies": {
"AutoMapper.Extensions.Microsoft.DependencyInjection": "[12.0.1, )", "AutoMapper.Extensions.Microsoft.DependencyInjection": "[12.0.1, )",
"Core": "[2023.10.2, )", "Core": "[2023.10.3, )",
"Microsoft.EntityFrameworkCore.Relational": "[7.0.5, )", "Microsoft.EntityFrameworkCore.Relational": "[7.0.5, )",
"Microsoft.EntityFrameworkCore.SqlServer": "[7.0.5, )", "Microsoft.EntityFrameworkCore.SqlServer": "[7.0.5, )",
"Microsoft.EntityFrameworkCore.Sqlite": "[7.0.5, )", "Microsoft.EntityFrameworkCore.Sqlite": "[7.0.5, )",
@ -2668,9 +2644,9 @@
"sharedweb": { "sharedweb": {
"type": "Project", "type": "Project",
"dependencies": { "dependencies": {
"Core": "[2023.10.2, )", "Core": "[2023.10.3, )",
"Infrastructure.Dapper": "[2023.10.2, )", "Infrastructure.Dapper": "[2023.10.3, )",
"Infrastructure.EntityFramework": "[2023.10.2, )" "Infrastructure.EntityFramework": "[2023.10.3, )"
} }
} }
} }

View File

@ -193,6 +193,24 @@
"Microsoft.Win32.Registry": "5.0.0" "Microsoft.Win32.Registry": "5.0.0"
} }
}, },
"Duende.IdentityServer": {
"type": "Transitive",
"resolved": "6.0.4",
"contentHash": "4HVjzx1F8v5J+U7oa8RGAQGj2QzmzNSu87r18Sh+dlh10uyZZL8teAaT/FaVLDObnfItGdPFvN8mwpF/HkI3Xw==",
"dependencies": {
"Duende.IdentityServer.Storage": "6.0.4",
"Microsoft.AspNetCore.Authentication.OpenIdConnect": "6.0.0"
}
},
"Duende.IdentityServer.Storage": {
"type": "Transitive",
"resolved": "6.0.4",
"contentHash": "s5gAjfbpr2IMgI+fU2Nx+2AZdzstmbt9gpo13iX7GwvqSeSaBVqj9ZskAN0R2KF1OemPdZuGnfaTcevdXMUrrw==",
"dependencies": {
"IdentityModel": "6.0.0",
"Microsoft.AspNetCore.DataProtection.Abstractions": "6.0.0"
}
},
"Fido2": { "Fido2": {
"type": "Transitive", "type": "Transitive",
"resolved": "3.0.1", "resolved": "3.0.1",
@ -229,49 +247,8 @@
}, },
"IdentityModel": { "IdentityModel": {
"type": "Transitive", "type": "Transitive",
"resolved": "4.4.0", "resolved": "6.0.0",
"contentHash": "b18wrIx5wnZlMxAX7oVsE+nDtAJ4hajYlH0xPlaRvo4r/fz08K6pPeZvbiqS9nfNbzfIgLFmNX+FL9qR9ZR5PA==", "contentHash": "eVHCR7a6m/dm5RFcBzE3qs/Jg5j9R5Rjpu8aTOv9e4AFvaQtBXb5ah7kmwU+YwA0ufRwz4wf1hnIvsD2hSnI4g=="
"dependencies": {
"Newtonsoft.Json": "11.0.2",
"System.Text.Encodings.Web": "4.7.0"
}
},
"IdentityModel.AspNetCore.OAuth2Introspection": {
"type": "Transitive",
"resolved": "4.0.1",
"contentHash": "ZNdMZMaj9fqR3j50vYsu+1U3QGd6n8+fqwf+a8mCTcmXGor+HgFDfdq0mM34bsmD6uEgAQup7sv2ZW5kR36dbA==",
"dependencies": {
"IdentityModel": "4.0.0"
}
},
"IdentityServer4": {
"type": "Transitive",
"resolved": "4.1.2",
"contentHash": "blaxxGuOA7v/w1q+fxn97wZ+x2ecG1ZD4mc/N/ZOXMNeFZZhqv+4LF26Gecyik3nWrJPmbMEtQbLmRsKG8k61w==",
"dependencies": {
"IdentityModel": "4.4.0",
"IdentityServer4.Storage": "4.1.2",
"Microsoft.AspNetCore.Authentication.OpenIdConnect": "3.1.0",
"Microsoft.IdentityModel.Protocols.OpenIdConnect": "5.6.0",
"Newtonsoft.Json": "12.0.2"
}
},
"IdentityServer4.AccessTokenValidation": {
"type": "Transitive",
"resolved": "3.0.1",
"contentHash": "qu/M6UyN4o9NVep7q545Ms7hYAnsQqSdLbN1Fjjrn4m35lyBfeQPSSNzDryAKHbodyWOQfHaOqKEyMEJQ5Rpgw==",
"dependencies": {
"IdentityModel.AspNetCore.OAuth2Introspection": "4.0.1",
"Microsoft.AspNetCore.Authentication.JwtBearer": "3.0.0"
}
},
"IdentityServer4.Storage": {
"type": "Transitive",
"resolved": "4.1.2",
"contentHash": "KoSffyZyyeCNTIyJiZnCuPakJ1QbCHlpty6gbWUj/7yl+w0PXIchgmmJnJSvddzBb8iZ2xew/vGlxWUIP17P2g==",
"dependencies": {
"IdentityModel": "4.4.0"
}
}, },
"LaunchDarkly.Cache": { "LaunchDarkly.Cache": {
"type": "Transitive", "type": "Transitive",
@ -363,10 +340,10 @@
}, },
"Microsoft.AspNetCore.Authentication.OpenIdConnect": { "Microsoft.AspNetCore.Authentication.OpenIdConnect": {
"type": "Transitive", "type": "Transitive",
"resolved": "3.1.0", "resolved": "6.0.0",
"contentHash": "O1cAQYUTU8EfRqwc5/rfTns4E4hKlFlg59fuKRrST+PzsxI6H07KqRN/JjdYhAuVYxF8jPnIGbj+zuc5paOWUw==", "contentHash": "cJxdro36spFzk/K2OFCddM6vZ+yoj6ug8mTFRH3Gdv1Pul/buSuCtfb/FSCp31UmS5S4C1315dU7wX3ErLFuDg==",
"dependencies": { "dependencies": {
"Microsoft.IdentityModel.Protocols.OpenIdConnect": "5.5.0" "Microsoft.IdentityModel.Protocols.OpenIdConnect": "6.10.0"
} }
}, },
"Microsoft.AspNetCore.Cryptography.Internal": { "Microsoft.AspNetCore.Cryptography.Internal": {
@ -399,8 +376,8 @@
}, },
"Microsoft.AspNetCore.DataProtection.Abstractions": { "Microsoft.AspNetCore.DataProtection.Abstractions": {
"type": "Transitive", "type": "Transitive",
"resolved": "3.1.32", "resolved": "6.0.0",
"contentHash": "MPL4iVyiaRxnOUY5VATHjvhDWaAEFb77KFiUxVRklv3Z3v+STofUr1UG/aCt1O9cgN7FVTDaC5A7U+zsLub8Xg==" "contentHash": "Z/UU4NEBm5UgNufJmw+j5baW26ytCOIZ0G7sZocPaOzsUeBon1bkM3lSMNZQG2GmDjAIVP2XMSODf2jzSGbibw=="
}, },
"Microsoft.Azure.Amqp": { "Microsoft.Azure.Amqp": {
"type": "Transitive", "type": "Transitive",
@ -2626,10 +2603,9 @@
"BitPay.Light": "[1.0.1907, )", "BitPay.Light": "[1.0.1907, )",
"Braintree": "[5.19.0, )", "Braintree": "[5.19.0, )",
"DnsClient": "[1.7.0, )", "DnsClient": "[1.7.0, )",
"Duende.IdentityServer": "[6.0.4, )",
"Fido2.AspNet": "[3.0.1, )", "Fido2.AspNet": "[3.0.1, )",
"Handlebars.Net": "[2.1.2, )", "Handlebars.Net": "[2.1.2, )",
"IdentityServer4": "[4.1.2, )",
"IdentityServer4.AccessTokenValidation": "[3.0.1, )",
"LaunchDarkly.ServerSdk": "[8.0.0, )", "LaunchDarkly.ServerSdk": "[8.0.0, )",
"MailKit": "[4.2.0, )", "MailKit": "[4.2.0, )",
"Microsoft.AspNetCore.Authentication.JwtBearer": "[6.0.4, )", "Microsoft.AspNetCore.Authentication.JwtBearer": "[6.0.4, )",
@ -2657,7 +2633,7 @@
"infrastructure.dapper": { "infrastructure.dapper": {
"type": "Project", "type": "Project",
"dependencies": { "dependencies": {
"Core": "[2023.10.2, )", "Core": "[2023.10.3, )",
"Dapper": "[2.0.123, )" "Dapper": "[2.0.123, )"
} }
}, },
@ -2665,7 +2641,7 @@
"type": "Project", "type": "Project",
"dependencies": { "dependencies": {
"AutoMapper.Extensions.Microsoft.DependencyInjection": "[12.0.1, )", "AutoMapper.Extensions.Microsoft.DependencyInjection": "[12.0.1, )",
"Core": "[2023.10.2, )", "Core": "[2023.10.3, )",
"Microsoft.EntityFrameworkCore.Relational": "[7.0.5, )", "Microsoft.EntityFrameworkCore.Relational": "[7.0.5, )",
"Microsoft.EntityFrameworkCore.SqlServer": "[7.0.5, )", "Microsoft.EntityFrameworkCore.SqlServer": "[7.0.5, )",
"Microsoft.EntityFrameworkCore.Sqlite": "[7.0.5, )", "Microsoft.EntityFrameworkCore.Sqlite": "[7.0.5, )",
@ -2677,9 +2653,9 @@
"sharedweb": { "sharedweb": {
"type": "Project", "type": "Project",
"dependencies": { "dependencies": {
"Core": "[2023.10.2, )", "Core": "[2023.10.3, )",
"Infrastructure.Dapper": "[2023.10.2, )", "Infrastructure.Dapper": "[2023.10.3, )",
"Infrastructure.EntityFramework": "[2023.10.2, )" "Infrastructure.EntityFramework": "[2023.10.3, )"
} }
} }
} }

View File

@ -1,6 +1,8 @@
using Bit.Core; using Bit.Core;
using Bit.Core.Auth.Enums;
using Bit.Core.Auth.Models.Api.Request.Accounts; using Bit.Core.Auth.Models.Api.Request.Accounts;
using Bit.Core.Auth.Models.Api.Response.Accounts; using Bit.Core.Auth.Models.Api.Response.Accounts;
using Bit.Core.Auth.Models.Business.Tokenables;
using Bit.Core.Auth.Services; using Bit.Core.Auth.Services;
using Bit.Core.Auth.Utilities; using Bit.Core.Auth.Utilities;
using Bit.Core.Enums; using Bit.Core.Enums;
@ -8,9 +10,9 @@ using Bit.Core.Exceptions;
using Bit.Core.Models.Data; using Bit.Core.Models.Data;
using Bit.Core.Repositories; using Bit.Core.Repositories;
using Bit.Core.Services; using Bit.Core.Services;
using Bit.Core.Tokens;
using Bit.Core.Utilities; using Bit.Core.Utilities;
using Bit.SharedWeb.Utilities; using Bit.SharedWeb.Utilities;
using Fido2NetLib;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
namespace Bit.Identity.Controllers; namespace Bit.Identity.Controllers;
@ -23,17 +25,21 @@ public class AccountsController : Controller
private readonly IUserRepository _userRepository; private readonly IUserRepository _userRepository;
private readonly IUserService _userService; private readonly IUserService _userService;
private readonly ICaptchaValidationService _captchaValidationService; private readonly ICaptchaValidationService _captchaValidationService;
private readonly IDataProtectorTokenFactory<WebAuthnLoginAssertionOptionsTokenable> _assertionOptionsDataProtector;
public AccountsController( public AccountsController(
ILogger<AccountsController> logger, ILogger<AccountsController> logger,
IUserRepository userRepository, IUserRepository userRepository,
IUserService userService, IUserService userService,
ICaptchaValidationService captchaValidationService) ICaptchaValidationService captchaValidationService,
IDataProtectorTokenFactory<WebAuthnLoginAssertionOptionsTokenable> assertionOptionsDataProtector)
{ {
_logger = logger; _logger = logger;
_userRepository = userRepository; _userRepository = userRepository;
_userService = userService; _userService = userService;
_captchaValidationService = captchaValidationService; _captchaValidationService = captchaValidationService;
_assertionOptionsDataProtector = assertionOptionsDataProtector;
} }
// Moved from API, If you modify this endpoint, please update API as well. Self hosted installs still use the API endpoints. // Moved from API, If you modify this endpoint, please update API as well. Self hosted installs still use the API endpoints.
@ -75,36 +81,19 @@ public class AccountsController : Controller
return new PreloginResponseModel(kdfInformation); return new PreloginResponseModel(kdfInformation);
} }
[HttpPost("webauthn-assertion-options")] [HttpGet("webauthn/assertion-options")]
[ApiExplorerSettings(IgnoreApi = true)] // Disable Swagger due to CredentialCreateOptions not converting properly
[RequireFeature(FeatureFlagKeys.PasswordlessLogin)] [RequireFeature(FeatureFlagKeys.PasswordlessLogin)]
// TODO: Create proper models for this call public WebAuthnLoginAssertionOptionsResponseModel GetWebAuthnLoginAssertionOptions()
public async Task<AssertionOptions> PostWebAuthnAssertionOptions([FromBody] PreloginRequestModel model)
{ {
var user = await _userRepository.GetByEmailAsync(model.Email); var options = _userService.StartWebAuthnLoginAssertion();
if (user == null)
{
// TODO: return something? possible enumeration attacks with this response
return new AssertionOptions();
}
var options = await _userService.StartWebAuthnLoginAssertionAsync(user); var tokenable = new WebAuthnLoginAssertionOptionsTokenable(WebAuthnLoginAssertionOptionsScope.Authentication, options);
return options; var token = _assertionOptionsDataProtector.Protect(tokenable);
}
[HttpPost("webauthn-assertion")] return new WebAuthnLoginAssertionOptionsResponseModel
[RequireFeature(FeatureFlagKeys.PasswordlessLogin)]
// TODO: Create proper models for this call
public async Task<string> PostWebAuthnAssertion([FromBody] PreloginRequestModel model)
{ {
var user = await _userRepository.GetByEmailAsync(model.Email); Options = options,
if (user == null) Token = token
{ };
// TODO: proper response here?
throw new BadRequestException();
}
var token = await _userService.CompleteWebAuthLoginAssertionAsync(null, user);
return token;
} }
} }

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