1
0
mirror of https://github.com/bitwarden/server.git synced 2025-07-01 16:12:49 -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",
"configurations": [
"Identity",
"API"
"run-Identity",
"run-API"
],
"presentation": {
"hidden": false,
"group": "AA_compounds",
"order": 1
},
"preLaunchTask": "buildIdentityApi",
"stopAll": true
},
{
"name": "Admin, API, Identity",
"configurations": [
"Admin",
"API",
"Identity"
"run-Admin",
"run-API",
"run-Identity"
],
"presentation": {
"hidden": false,
"group": "AA_compounds",
"order": 3
},
"preLaunchTask": "buildIdentityApiAdmin",
"stopAll": true
},
{
"name": "Full Server",
"configurations": [
"Admin",
"API",
"EventsProcessor",
"Identity",
"Sso",
"Icons",
"Billing",
"Notifications"
"run-Admin",
"run-API",
"run-EventsProcessor",
"run-Identity",
"run-Sso",
"run-Icons",
"run-Billing",
"run-Notifications"
],
"presentation": {
"hidden": false,
"group": "AA_compounds",
"order": 4
},
"preLaunchTask": "buildFullServer",
"stopAll": true
},
{
"name": "Self Host: Bit",
"configurations": [
"Admin-SelfHost",
"API-SelfHost",
"EventsProcessor-SelfHost",
"Identity-SelfHost",
"Sso-SelfHost",
"Notifications-SelfHost"
"run-Admin-SelfHost",
"run-API-SelfHost",
"run-EventsProcessor-SelfHost",
"run-Identity-SelfHost",
"run-Sso-SelfHost",
"run-Notifications-SelfHost"
],
"presentation": {
"hidden": false,
"group": "AA_compounds",
"order": 2
},
"preLaunchTask": "buildSelfHostBit",
"stopAll": true
},
{
"name": "Self Host: OSS",
"configurations": [
"Admin-SelfHost",
"API-SelfHost",
"EventsProcessor-SelfHost",
"Identity-SelfHost",
"run-Admin-SelfHost",
"run-API-SelfHost",
"run-EventsProcessor-SelfHost",
"run-Identity-SelfHost",
],
"presentation": {
"hidden": false,
"group": "AA_compounds",
"order": 99
},
"preLaunchTask": "buildSelfHostOss",
"stopAll": true
}
],
"configurations": [
},
{
"name": "Identity",
"name": "Admin",
"configurations": [
"run-Admin"
],
"presentation": {
"hidden": false,
"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,
"type": "coreclr",
"request": "launch",
"preLaunchTask": "buildIdentity",
"program": "${workspaceFolder}/src/Identity/bin/Debug/net6.0/Identity.dll",
"args": [],
"cwd": "${workspaceFolder}/src/Identity",
@ -107,16 +264,13 @@
}
},
{
"name": "API",
"name": "run-API",
"presentation": {
"hidden": false,
"group": "cloud",
"order": 10
"hidden": true,
},
"requireExactSource": true,
"type": "coreclr",
"request": "launch",
"preLaunchTask": "buildAPI",
"program": "${workspaceFolder}/src/Api/bin/Debug/net6.0/Api.dll",
"args": [],
"cwd": "${workspaceFolder}/src/Api",
@ -129,16 +283,13 @@
}
},
{
"name": "Billing",
"name": "run-Billing",
"presentation": {
"hidden": false,
"group": "cloud",
"order": 10
"hidden": true,
},
"requireExactSource": true,
"type": "coreclr",
"request": "launch",
"preLaunchTask": "buildBilling",
"program": "${workspaceFolder}/src/Billing/bin/Debug/net6.0/Billing.dll",
"args": [],
"cwd": "${workspaceFolder}/src/Billing",
@ -151,16 +302,13 @@
}
},
{
"name": "Admin",
"name": "run-Admin",
"presentation": {
"hidden": false,
"group": "cloud",
"order": 20
"hidden": true,
},
"requireExactSource": true,
"type": "coreclr",
"request": "launch",
"preLaunchTask": "buildAdmin",
"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",
"args": [],
@ -175,16 +323,13 @@
}
},
{
"name": "Sso",
"name": "run-Sso",
"presentation": {
"hidden": false,
"group": "cloud",
"order": 50
"hidden": true,
},
"requireExactSource": true,
"type": "coreclr",
"request": "launch",
"preLaunchTask": "buildSso",
"program": "${workspaceFolder}/bitwarden_license/src/Sso/bin/Debug/net6.0/Sso.dll",
"args": [],
"cwd": "${workspaceFolder}/bitwarden_license/src/Sso",
@ -197,16 +342,13 @@
}
},
{
"name": "EventsProcessor",
"name": "run-EventsProcessor",
"presentation": {
"hidden": false,
"group": "cloud",
"order": 90
"hidden": true,
},
"requireExactSource": true,
"type": "coreclr",
"request": "launch",
"preLaunchTask": "buildEventsProcessor",
"program": "${workspaceFolder}/src/EventsProcessor/bin/Debug/net6.0/EventsProcessor.dll",
"args": [],
"cwd": "${workspaceFolder}/src/EventsProcessor",
@ -219,16 +361,13 @@
}
},
{
"name": "Icons",
"name": "run-Icons",
"presentation": {
"hidden": false,
"group": "cloud",
"order": 90
"hidden": true,
},
"requireExactSource": true,
"type": "coreclr",
"request": "launch",
"preLaunchTask": "buildIcons",
"program": "${workspaceFolder}/src/Icons/bin/Debug/net6.0/Icons.dll",
"args": [],
"cwd": "${workspaceFolder}/src/Icons",
@ -241,16 +380,13 @@
}
},
{
"name": "Notifications",
"name": "run-Notifications",
"presentation": {
"hidden": true,
"group": "cloud",
"order": 100
},
"requireExactSource": true,
"type": "coreclr",
"request": "launch",
"preLaunchTask": "buildNotifications",
"program": "${workspaceFolder}/src/Notifications/bin/Debug/net6.0/Notifications.dll",
"args": [],
"cwd": "${workspaceFolder}/src/Notifications",
@ -263,16 +399,13 @@
}
},
{
"name": "Identity-SelfHost",
"name": "run-Identity-SelfHost",
"presentation": {
"hidden": true,
"group": "self-host",
"order": 999
},
"requireExactSource": true,
"type": "coreclr",
"request": "launch",
"preLaunchTask": "buildIdentity",
"program": "${workspaceFolder}/src/Identity/bin/Debug/net6.0/Identity.dll",
"args": [],
"cwd": "${workspaceFolder}/src/Identity",
@ -287,16 +420,13 @@
}
},
{
"name": "API-SelfHost",
"name": "run-API-SelfHost",
"presentation": {
"hidden": true,
"group": "self-host",
"order": 999
},
"requireExactSource": true,
"type": "coreclr",
"request": "launch",
"preLaunchTask": "buildAPI",
"program": "${workspaceFolder}/src/Api/bin/Debug/net6.0/Api.dll",
"args": [],
"cwd": "${workspaceFolder}/src/Api",
@ -311,16 +441,13 @@
}
},
{
"name": "Admin-SelfHost",
"name": "run-Admin-SelfHost",
"presentation": {
"hidden": true,
"group": "self-host",
"order": 999
},
"requireExactSource": true,
"type": "coreclr",
"request": "launch",
"preLaunchTask": "buildAdmin",
"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",
"args": [],
@ -337,16 +464,13 @@
}
},
{
"name": "Sso-SelfHost",
"name": "run-Sso-SelfHost",
"presentation": {
"hidden": true,
"group": "self-host",
"order": 999
},
"requireExactSource": true,
"type": "coreclr",
"request": "launch",
"preLaunchTask": "buildSso",
"program": "${workspaceFolder}/bitwarden_license/src/Sso/bin/Debug/net6.0/Sso.dll",
"args": [],
"cwd": "${workspaceFolder}/bitwarden_license/src/Sso",
@ -361,16 +485,13 @@
}
},
{
"name": "Notifications-SelfHost",
"name": "run-Notifications-SelfHost",
"presentation": {
"hidden": true,
"group": "self-host",
"order": 999
},
"requireExactSource": true,
"type": "coreclr",
"request": "launch",
"preLaunchTask": "buildNotifications",
"program": "${workspaceFolder}/src/Notifications/bin/Debug/net6.0/Notifications.dll",
"args": [],
"cwd": "${workspaceFolder}/src/Notifications",
@ -385,16 +506,13 @@
}
},
{
"name": "EventsProcessor-SelfHost",
"name": "run-EventsProcessor-SelfHost",
"presentation": {
"hidden": true,
"group": "self-host",
"order": 999
},
"requireExactSource": true,
"type": "coreclr",
"request": "launch",
"preLaunchTask": "buildEventsProcessor",
"program": "${workspaceFolder}/src/EventsProcessor/bin/Debug/net6.0/EventsProcessor.dll",
"args": [],
"cwd": "${workspaceFolder}/src/EventsProcessor",

59
.vscode/tasks.json vendored
View File

@ -1,6 +1,65 @@
{
"version": "2.0.0",
"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",
"command": "dotnet",

View File

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

View File

@ -162,6 +162,24 @@
"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": {
"type": "Transitive",
"resolved": "3.0.1",
@ -198,49 +216,8 @@
},
"IdentityModel": {
"type": "Transitive",
"resolved": "4.4.0",
"contentHash": "b18wrIx5wnZlMxAX7oVsE+nDtAJ4hajYlH0xPlaRvo4r/fz08K6pPeZvbiqS9nfNbzfIgLFmNX+FL9qR9ZR5PA==",
"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"
}
"resolved": "6.0.0",
"contentHash": "eVHCR7a6m/dm5RFcBzE3qs/Jg5j9R5Rjpu8aTOv9e4AFvaQtBXb5ah7kmwU+YwA0ufRwz4wf1hnIvsD2hSnI4g=="
},
"LaunchDarkly.Cache": {
"type": "Transitive",
@ -318,10 +295,10 @@
},
"Microsoft.AspNetCore.Authentication.OpenIdConnect": {
"type": "Transitive",
"resolved": "3.1.0",
"contentHash": "O1cAQYUTU8EfRqwc5/rfTns4E4hKlFlg59fuKRrST+PzsxI6H07KqRN/JjdYhAuVYxF8jPnIGbj+zuc5paOWUw==",
"resolved": "6.0.0",
"contentHash": "cJxdro36spFzk/K2OFCddM6vZ+yoj6ug8mTFRH3Gdv1Pul/buSuCtfb/FSCp31UmS5S4C1315dU7wX3ErLFuDg==",
"dependencies": {
"Microsoft.IdentityModel.Protocols.OpenIdConnect": "5.5.0"
"Microsoft.IdentityModel.Protocols.OpenIdConnect": "6.10.0"
}
},
"Microsoft.AspNetCore.Cryptography.Internal": {
@ -354,8 +331,8 @@
},
"Microsoft.AspNetCore.DataProtection.Abstractions": {
"type": "Transitive",
"resolved": "3.1.32",
"contentHash": "MPL4iVyiaRxnOUY5VATHjvhDWaAEFb77KFiUxVRklv3Z3v+STofUr1UG/aCt1O9cgN7FVTDaC5A7U+zsLub8Xg=="
"resolved": "6.0.0",
"contentHash": "Z/UU4NEBm5UgNufJmw+j5baW26ytCOIZ0G7sZocPaOzsUeBon1bkM3lSMNZQG2GmDjAIVP2XMSODf2jzSGbibw=="
},
"Microsoft.Azure.Amqp": {
"type": "Transitive",
@ -2450,10 +2427,9 @@
"BitPay.Light": "[1.0.1907, )",
"Braintree": "[5.19.0, )",
"DnsClient": "[1.7.0, )",
"Duende.IdentityServer": "[6.0.4, )",
"Fido2.AspNet": "[3.0.1, )",
"Handlebars.Net": "[2.1.2, )",
"IdentityServer4": "[4.1.2, )",
"IdentityServer4.AccessTokenValidation": "[3.0.1, )",
"LaunchDarkly.ServerSdk": "[8.0.0, )",
"MailKit": "[4.2.0, )",
"Microsoft.AspNetCore.Authentication.JwtBearer": "[6.0.4, )",

View File

@ -180,6 +180,24 @@
"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": {
"type": "Transitive",
"resolved": "3.0.1",
@ -216,49 +234,8 @@
},
"IdentityModel": {
"type": "Transitive",
"resolved": "4.4.0",
"contentHash": "b18wrIx5wnZlMxAX7oVsE+nDtAJ4hajYlH0xPlaRvo4r/fz08K6pPeZvbiqS9nfNbzfIgLFmNX+FL9qR9ZR5PA==",
"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"
}
"resolved": "6.0.0",
"contentHash": "eVHCR7a6m/dm5RFcBzE3qs/Jg5j9R5Rjpu8aTOv9e4AFvaQtBXb5ah7kmwU+YwA0ufRwz4wf1hnIvsD2hSnI4g=="
},
"LaunchDarkly.Cache": {
"type": "Transitive",
@ -350,10 +327,10 @@
},
"Microsoft.AspNetCore.Authentication.OpenIdConnect": {
"type": "Transitive",
"resolved": "3.1.0",
"contentHash": "O1cAQYUTU8EfRqwc5/rfTns4E4hKlFlg59fuKRrST+PzsxI6H07KqRN/JjdYhAuVYxF8jPnIGbj+zuc5paOWUw==",
"resolved": "6.0.0",
"contentHash": "cJxdro36spFzk/K2OFCddM6vZ+yoj6ug8mTFRH3Gdv1Pul/buSuCtfb/FSCp31UmS5S4C1315dU7wX3ErLFuDg==",
"dependencies": {
"Microsoft.IdentityModel.Protocols.OpenIdConnect": "5.5.0"
"Microsoft.IdentityModel.Protocols.OpenIdConnect": "6.10.0"
}
},
"Microsoft.AspNetCore.Cryptography.Internal": {
@ -386,8 +363,8 @@
},
"Microsoft.AspNetCore.DataProtection.Abstractions": {
"type": "Transitive",
"resolved": "3.1.32",
"contentHash": "MPL4iVyiaRxnOUY5VATHjvhDWaAEFb77KFiUxVRklv3Z3v+STofUr1UG/aCt1O9cgN7FVTDaC5A7U+zsLub8Xg=="
"resolved": "6.0.0",
"contentHash": "Z/UU4NEBm5UgNufJmw+j5baW26ytCOIZ0G7sZocPaOzsUeBon1bkM3lSMNZQG2GmDjAIVP2XMSODf2jzSGbibw=="
},
"Microsoft.Azure.Amqp": {
"type": "Transitive",
@ -2613,10 +2590,9 @@
"BitPay.Light": "[1.0.1907, )",
"Braintree": "[5.19.0, )",
"DnsClient": "[1.7.0, )",
"Duende.IdentityServer": "[6.0.4, )",
"Fido2.AspNet": "[3.0.1, )",
"Handlebars.Net": "[2.1.2, )",
"IdentityServer4": "[4.1.2, )",
"IdentityServer4.AccessTokenValidation": "[3.0.1, )",
"LaunchDarkly.ServerSdk": "[8.0.0, )",
"MailKit": "[4.2.0, )",
"Microsoft.AspNetCore.Authentication.JwtBearer": "[6.0.4, )",
@ -2645,7 +2621,7 @@
"type": "Project",
"dependencies": {
"AutoMapper.Extensions.Microsoft.DependencyInjection": "[12.0.1, )",
"Core": "[2023.10.2, )",
"Core": "[2023.10.3, )",
"Microsoft.EntityFrameworkCore.Relational": "[7.0.5, )",
"Microsoft.EntityFrameworkCore.SqlServer": "[7.0.5, )",
"Microsoft.EntityFrameworkCore.Sqlite": "[7.0.5, )",

View File

@ -184,6 +184,24 @@
"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": {
"type": "Transitive",
"resolved": "3.0.1",
@ -220,49 +238,8 @@
},
"IdentityModel": {
"type": "Transitive",
"resolved": "4.4.0",
"contentHash": "b18wrIx5wnZlMxAX7oVsE+nDtAJ4hajYlH0xPlaRvo4r/fz08K6pPeZvbiqS9nfNbzfIgLFmNX+FL9qR9ZR5PA==",
"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"
}
"resolved": "6.0.0",
"contentHash": "eVHCR7a6m/dm5RFcBzE3qs/Jg5j9R5Rjpu8aTOv9e4AFvaQtBXb5ah7kmwU+YwA0ufRwz4wf1hnIvsD2hSnI4g=="
},
"LaunchDarkly.Cache": {
"type": "Transitive",
@ -354,10 +331,10 @@
},
"Microsoft.AspNetCore.Authentication.OpenIdConnect": {
"type": "Transitive",
"resolved": "3.1.0",
"contentHash": "O1cAQYUTU8EfRqwc5/rfTns4E4hKlFlg59fuKRrST+PzsxI6H07KqRN/JjdYhAuVYxF8jPnIGbj+zuc5paOWUw==",
"resolved": "6.0.0",
"contentHash": "cJxdro36spFzk/K2OFCddM6vZ+yoj6ug8mTFRH3Gdv1Pul/buSuCtfb/FSCp31UmS5S4C1315dU7wX3ErLFuDg==",
"dependencies": {
"Microsoft.IdentityModel.Protocols.OpenIdConnect": "5.5.0"
"Microsoft.IdentityModel.Protocols.OpenIdConnect": "6.10.0"
}
},
"Microsoft.AspNetCore.Cryptography.Internal": {
@ -390,8 +367,8 @@
},
"Microsoft.AspNetCore.DataProtection.Abstractions": {
"type": "Transitive",
"resolved": "3.1.32",
"contentHash": "MPL4iVyiaRxnOUY5VATHjvhDWaAEFb77KFiUxVRklv3Z3v+STofUr1UG/aCt1O9cgN7FVTDaC5A7U+zsLub8Xg=="
"resolved": "6.0.0",
"contentHash": "Z/UU4NEBm5UgNufJmw+j5baW26ytCOIZ0G7sZocPaOzsUeBon1bkM3lSMNZQG2GmDjAIVP2XMSODf2jzSGbibw=="
},
"Microsoft.Azure.Amqp": {
"type": "Transitive",
@ -2617,10 +2594,9 @@
"BitPay.Light": "[1.0.1907, )",
"Braintree": "[5.19.0, )",
"DnsClient": "[1.7.0, )",
"Duende.IdentityServer": "[6.0.4, )",
"Fido2.AspNet": "[3.0.1, )",
"Handlebars.Net": "[2.1.2, )",
"IdentityServer4": "[4.1.2, )",
"IdentityServer4.AccessTokenValidation": "[3.0.1, )",
"LaunchDarkly.ServerSdk": "[8.0.0, )",
"MailKit": "[4.2.0, )",
"Microsoft.AspNetCore.Authentication.JwtBearer": "[6.0.4, )",
@ -2648,7 +2624,7 @@
"infrastructure.dapper": {
"type": "Project",
"dependencies": {
"Core": "[2023.10.2, )",
"Core": "[2023.10.3, )",
"Dapper": "[2.0.123, )"
}
},
@ -2656,7 +2632,7 @@
"type": "Project",
"dependencies": {
"AutoMapper.Extensions.Microsoft.DependencyInjection": "[12.0.1, )",
"Core": "[2023.10.2, )",
"Core": "[2023.10.3, )",
"Microsoft.EntityFrameworkCore.Relational": "[7.0.5, )",
"Microsoft.EntityFrameworkCore.SqlServer": "[7.0.5, )",
"Microsoft.EntityFrameworkCore.Sqlite": "[7.0.5, )",
@ -2668,9 +2644,9 @@
"sharedweb": {
"type": "Project",
"dependencies": {
"Core": "[2023.10.2, )",
"Infrastructure.Dapper": "[2023.10.2, )",
"Infrastructure.EntityFramework": "[2023.10.2, )"
"Core": "[2023.10.3, )",
"Infrastructure.Dapper": "[2023.10.3, )",
"Infrastructure.EntityFramework": "[2023.10.3, )"
}
}
}

View File

@ -1,5 +1,7 @@
using System.Security.Claims;
using Bit.Core;
using Bit.Core.AdminConsole.Enums;
using Bit.Core.AdminConsole.Repositories;
using Bit.Core.Auth.Entities;
using Bit.Core.Auth.Enums;
using Bit.Core.Auth.Models;
@ -16,14 +18,15 @@ using Bit.Core.Tokens;
using Bit.Core.Utilities;
using Bit.Sso.Models;
using Bit.Sso.Utilities;
using Duende.IdentityServer;
using Duende.IdentityServer.Extensions;
using Duende.IdentityServer.Services;
using Duende.IdentityServer.Stores;
using IdentityModel;
using IdentityServer4;
using IdentityServer4.Extensions;
using IdentityServer4.Services;
using IdentityServer4.Stores;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using DIM = Duende.IdentityServer.Models;
namespace Bit.Sso.Controllers;
@ -717,7 +720,7 @@ public class AccountController : Controller
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)
&& !context.RedirectUri.StartsWith("http", StringComparison.Ordinal);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -7,9 +7,9 @@ using Bit.Core.Settings;
using Bit.Core.Utilities;
using Bit.Sso.Models;
using Bit.Sso.Utilities;
using Duende.IdentityServer;
using Duende.IdentityServer.Infrastructure;
using IdentityModel;
using IdentityServer4;
using IdentityServer4.Infrastructure;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.Extensions.Options;
@ -34,7 +34,7 @@ public class DynamicAuthenticationSchemeProvider : AuthenticationSchemeProvider
private readonly Dictionary<string, DynamicAuthenticationScheme> _cachedSchemes;
private readonly Dictionary<string, DynamicAuthenticationScheme> _cachedHandlerSchemes;
private readonly SemaphoreSlim _semaphore;
private readonly IHttpContextAccessor _httpContextAccessor;
private readonly IServiceProvider _serviceProvider;
private DateTime? _lastSchemeLoad;
private IEnumerable<DynamicAuthenticationScheme> _schemesCopy = Array.Empty<DynamicAuthenticationScheme>();
@ -50,7 +50,7 @@ public class DynamicAuthenticationSchemeProvider : AuthenticationSchemeProvider
ILogger<DynamicAuthenticationSchemeProvider> logger,
GlobalSettings globalSettings,
SamlEnvironment samlEnvironment,
IHttpContextAccessor httpContextAccessor)
IServiceProvider serviceProvider)
: base(options)
{
_oidcPostConfigureOptions = oidcPostConfigureOptions;
@ -77,7 +77,7 @@ public class DynamicAuthenticationSchemeProvider : AuthenticationSchemeProvider
_cachedSchemes = new Dictionary<string, DynamicAuthenticationScheme>();
_cachedHandlerSchemes = new Dictionary<string, DynamicAuthenticationScheme>();
_semaphore = new SemaphoreSlim(1);
_httpContextAccessor = httpContextAccessor ?? throw new ArgumentNullException(nameof(httpContextAccessor));
_serviceProvider = serviceProvider ?? throw new ArgumentNullException(nameof(serviceProvider));
}
private bool CacheIsValid
@ -324,7 +324,7 @@ public class DynamicAuthenticationSchemeProvider : AuthenticationSchemeProvider
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)
if (!string.IsNullOrWhiteSpace(config.AcrValues))

View File

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

View File

@ -209,6 +209,24 @@
"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": {
"type": "Transitive",
"resolved": "3.0.1",
@ -245,49 +263,8 @@
},
"IdentityModel": {
"type": "Transitive",
"resolved": "4.4.0",
"contentHash": "b18wrIx5wnZlMxAX7oVsE+nDtAJ4hajYlH0xPlaRvo4r/fz08K6pPeZvbiqS9nfNbzfIgLFmNX+FL9qR9ZR5PA==",
"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"
}
"resolved": "6.0.0",
"contentHash": "eVHCR7a6m/dm5RFcBzE3qs/Jg5j9R5Rjpu8aTOv9e4AFvaQtBXb5ah7kmwU+YwA0ufRwz4wf1hnIvsD2hSnI4g=="
},
"LaunchDarkly.Cache": {
"type": "Transitive",
@ -421,10 +398,10 @@
},
"Microsoft.AspNetCore.Authentication.OpenIdConnect": {
"type": "Transitive",
"resolved": "3.1.0",
"contentHash": "O1cAQYUTU8EfRqwc5/rfTns4E4hKlFlg59fuKRrST+PzsxI6H07KqRN/JjdYhAuVYxF8jPnIGbj+zuc5paOWUw==",
"resolved": "6.0.0",
"contentHash": "cJxdro36spFzk/K2OFCddM6vZ+yoj6ug8mTFRH3Gdv1Pul/buSuCtfb/FSCp31UmS5S4C1315dU7wX3ErLFuDg==",
"dependencies": {
"Microsoft.IdentityModel.Protocols.OpenIdConnect": "5.5.0"
"Microsoft.IdentityModel.Protocols.OpenIdConnect": "6.10.0"
}
},
"Microsoft.AspNetCore.Cryptography.Internal": {
@ -457,8 +434,8 @@
},
"Microsoft.AspNetCore.DataProtection.Abstractions": {
"type": "Transitive",
"resolved": "3.1.32",
"contentHash": "MPL4iVyiaRxnOUY5VATHjvhDWaAEFb77KFiUxVRklv3Z3v+STofUr1UG/aCt1O9cgN7FVTDaC5A7U+zsLub8Xg=="
"resolved": "6.0.0",
"contentHash": "Z/UU4NEBm5UgNufJmw+j5baW26ytCOIZ0G7sZocPaOzsUeBon1bkM3lSMNZQG2GmDjAIVP2XMSODf2jzSGbibw=="
},
"Microsoft.AspNetCore.Http.Abstractions": {
"type": "Transitive",
@ -2777,10 +2754,9 @@
"BitPay.Light": "[1.0.1907, )",
"Braintree": "[5.19.0, )",
"DnsClient": "[1.7.0, )",
"Duende.IdentityServer": "[6.0.4, )",
"Fido2.AspNet": "[3.0.1, )",
"Handlebars.Net": "[2.1.2, )",
"IdentityServer4": "[4.1.2, )",
"IdentityServer4.AccessTokenValidation": "[3.0.1, )",
"LaunchDarkly.ServerSdk": "[8.0.0, )",
"MailKit": "[4.2.0, )",
"Microsoft.AspNetCore.Authentication.JwtBearer": "[6.0.4, )",
@ -2808,7 +2784,7 @@
"infrastructure.dapper": {
"type": "Project",
"dependencies": {
"Core": "[2023.10.2, )",
"Core": "[2023.10.3, )",
"Dapper": "[2.0.123, )"
}
},
@ -2816,7 +2792,7 @@
"type": "Project",
"dependencies": {
"AutoMapper.Extensions.Microsoft.DependencyInjection": "[12.0.1, )",
"Core": "[2023.10.2, )",
"Core": "[2023.10.3, )",
"Microsoft.EntityFrameworkCore.Relational": "[7.0.5, )",
"Microsoft.EntityFrameworkCore.SqlServer": "[7.0.5, )",
"Microsoft.EntityFrameworkCore.Sqlite": "[7.0.5, )",
@ -2828,9 +2804,9 @@
"sharedweb": {
"type": "Project",
"dependencies": {
"Core": "[2023.10.2, )",
"Infrastructure.Dapper": "[2023.10.2, )",
"Infrastructure.EntityFramework": "[2023.10.2, )"
"Core": "[2023.10.3, )",
"Infrastructure.Dapper": "[2023.10.3, )",
"Infrastructure.EntityFramework": "[2023.10.3, )"
}
}
}

View File

@ -239,6 +239,24 @@
"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": {
"type": "Transitive",
"resolved": "2.1.1",
@ -283,49 +301,8 @@
},
"IdentityModel": {
"type": "Transitive",
"resolved": "4.4.0",
"contentHash": "b18wrIx5wnZlMxAX7oVsE+nDtAJ4hajYlH0xPlaRvo4r/fz08K6pPeZvbiqS9nfNbzfIgLFmNX+FL9qR9ZR5PA==",
"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"
}
"resolved": "6.0.0",
"contentHash": "eVHCR7a6m/dm5RFcBzE3qs/Jg5j9R5Rjpu8aTOv9e4AFvaQtBXb5ah7kmwU+YwA0ufRwz4wf1hnIvsD2hSnI4g=="
},
"Kralizek.AutoFixture.Extensions.MockHttp": {
"type": "Transitive",
@ -412,10 +389,10 @@
},
"Microsoft.AspNetCore.Authentication.OpenIdConnect": {
"type": "Transitive",
"resolved": "3.1.0",
"contentHash": "O1cAQYUTU8EfRqwc5/rfTns4E4hKlFlg59fuKRrST+PzsxI6H07KqRN/JjdYhAuVYxF8jPnIGbj+zuc5paOWUw==",
"resolved": "6.0.0",
"contentHash": "cJxdro36spFzk/K2OFCddM6vZ+yoj6ug8mTFRH3Gdv1Pul/buSuCtfb/FSCp31UmS5S4C1315dU7wX3ErLFuDg==",
"dependencies": {
"Microsoft.IdentityModel.Protocols.OpenIdConnect": "5.5.0"
"Microsoft.IdentityModel.Protocols.OpenIdConnect": "6.10.0"
}
},
"Microsoft.AspNetCore.Cryptography.Internal": {
@ -448,8 +425,8 @@
},
"Microsoft.AspNetCore.DataProtection.Abstractions": {
"type": "Transitive",
"resolved": "3.1.32",
"contentHash": "MPL4iVyiaRxnOUY5VATHjvhDWaAEFb77KFiUxVRklv3Z3v+STofUr1UG/aCt1O9cgN7FVTDaC5A7U+zsLub8Xg=="
"resolved": "6.0.0",
"contentHash": "Z/UU4NEBm5UgNufJmw+j5baW26ytCOIZ0G7sZocPaOzsUeBon1bkM3lSMNZQG2GmDjAIVP2XMSODf2jzSGbibw=="
},
"Microsoft.Azure.Amqp": {
"type": "Transitive",
@ -2680,7 +2657,7 @@
"commercial.core": {
"type": "Project",
"dependencies": {
"Core": "[2023.10.2, )"
"Core": "[2023.10.3, )"
}
},
"common": {
@ -2688,7 +2665,7 @@
"dependencies": {
"AutoFixture.AutoNSubstitute": "[4.17.0, )",
"AutoFixture.Xunit2": "[4.17.0, )",
"Core": "[2023.10.2, )",
"Core": "[2023.10.3, )",
"Kralizek.AutoFixture.Extensions.MockHttp": "[1.2.0, )",
"Microsoft.NET.Test.Sdk": "[17.1.0, )",
"NSubstitute": "[4.3.0, )",
@ -2710,10 +2687,9 @@
"BitPay.Light": "[1.0.1907, )",
"Braintree": "[5.19.0, )",
"DnsClient": "[1.7.0, )",
"Duende.IdentityServer": "[6.0.4, )",
"Fido2.AspNet": "[3.0.1, )",
"Handlebars.Net": "[2.1.2, )",
"IdentityServer4": "[4.1.2, )",
"IdentityServer4.AccessTokenValidation": "[3.0.1, )",
"LaunchDarkly.ServerSdk": "[8.0.0, )",
"MailKit": "[4.2.0, )",
"Microsoft.AspNetCore.Authentication.JwtBearer": "[6.0.4, )",
@ -2743,8 +2719,8 @@
"dependencies": {
"AutoFixture.AutoNSubstitute": "[4.17.0, )",
"AutoFixture.Xunit2": "[4.17.0, )",
"Common": "[2023.10.2, )",
"Core": "[2023.10.2, )",
"Common": "[2023.10.3, )",
"Core": "[2023.10.3, )",
"Kralizek.AutoFixture.Extensions.MockHttp": "[1.2.0, )",
"Microsoft.NET.Test.Sdk": "[17.1.0, )",
"NSubstitute": "[4.3.0, )",

View File

@ -282,6 +282,24 @@
"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": {
"type": "Transitive",
"resolved": "2.1.1",
@ -326,49 +344,8 @@
},
"IdentityModel": {
"type": "Transitive",
"resolved": "4.4.0",
"contentHash": "b18wrIx5wnZlMxAX7oVsE+nDtAJ4hajYlH0xPlaRvo4r/fz08K6pPeZvbiqS9nfNbzfIgLFmNX+FL9qR9ZR5PA==",
"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"
}
"resolved": "6.0.0",
"contentHash": "eVHCR7a6m/dm5RFcBzE3qs/Jg5j9R5Rjpu8aTOv9e4AFvaQtBXb5ah7kmwU+YwA0ufRwz4wf1hnIvsD2hSnI4g=="
},
"Kralizek.AutoFixture.Extensions.MockHttp": {
"type": "Transitive",
@ -469,10 +446,10 @@
},
"Microsoft.AspNetCore.Authentication.OpenIdConnect": {
"type": "Transitive",
"resolved": "3.1.0",
"contentHash": "O1cAQYUTU8EfRqwc5/rfTns4E4hKlFlg59fuKRrST+PzsxI6H07KqRN/JjdYhAuVYxF8jPnIGbj+zuc5paOWUw==",
"resolved": "6.0.0",
"contentHash": "cJxdro36spFzk/K2OFCddM6vZ+yoj6ug8mTFRH3Gdv1Pul/buSuCtfb/FSCp31UmS5S4C1315dU7wX3ErLFuDg==",
"dependencies": {
"Microsoft.IdentityModel.Protocols.OpenIdConnect": "5.5.0"
"Microsoft.IdentityModel.Protocols.OpenIdConnect": "6.10.0"
}
},
"Microsoft.AspNetCore.Cryptography.Internal": {
@ -505,8 +482,8 @@
},
"Microsoft.AspNetCore.DataProtection.Abstractions": {
"type": "Transitive",
"resolved": "3.1.32",
"contentHash": "MPL4iVyiaRxnOUY5VATHjvhDWaAEFb77KFiUxVRklv3Z3v+STofUr1UG/aCt1O9cgN7FVTDaC5A7U+zsLub8Xg=="
"resolved": "6.0.0",
"contentHash": "Z/UU4NEBm5UgNufJmw+j5baW26ytCOIZ0G7sZocPaOzsUeBon1bkM3lSMNZQG2GmDjAIVP2XMSODf2jzSGbibw=="
},
"Microsoft.AspNetCore.TestHost": {
"type": "Transitive",
@ -2997,7 +2974,7 @@
"dependencies": {
"AutoFixture.AutoNSubstitute": "[4.17.0, )",
"AutoFixture.Xunit2": "[4.17.0, )",
"Core": "[2023.10.2, )",
"Core": "[2023.10.3, )",
"Kralizek.AutoFixture.Extensions.MockHttp": "[1.2.0, )",
"Microsoft.NET.Test.Sdk": "[17.1.0, )",
"NSubstitute": "[4.3.0, )",
@ -3019,10 +2996,9 @@
"BitPay.Light": "[1.0.1907, )",
"Braintree": "[5.19.0, )",
"DnsClient": "[1.7.0, )",
"Duende.IdentityServer": "[6.0.4, )",
"Fido2.AspNet": "[3.0.1, )",
"Handlebars.Net": "[2.1.2, )",
"IdentityServer4": "[4.1.2, )",
"IdentityServer4.AccessTokenValidation": "[3.0.1, )",
"LaunchDarkly.ServerSdk": "[8.0.0, )",
"MailKit": "[4.2.0, )",
"Microsoft.AspNetCore.Authentication.JwtBearer": "[6.0.4, )",
@ -3050,15 +3026,15 @@
"identity": {
"type": "Project",
"dependencies": {
"Core": "[2023.10.2, )",
"SharedWeb": "[2023.10.2, )",
"Core": "[2023.10.3, )",
"SharedWeb": "[2023.10.3, )",
"Swashbuckle.AspNetCore.SwaggerGen": "[6.5.0, )"
}
},
"infrastructure.dapper": {
"type": "Project",
"dependencies": {
"Core": "[2023.10.2, )",
"Core": "[2023.10.3, )",
"Dapper": "[2.0.123, )"
}
},
@ -3066,7 +3042,7 @@
"type": "Project",
"dependencies": {
"AutoMapper.Extensions.Microsoft.DependencyInjection": "[12.0.1, )",
"Core": "[2023.10.2, )",
"Core": "[2023.10.3, )",
"Microsoft.EntityFrameworkCore.Relational": "[7.0.5, )",
"Microsoft.EntityFrameworkCore.SqlServer": "[7.0.5, )",
"Microsoft.EntityFrameworkCore.Sqlite": "[7.0.5, )",
@ -3078,8 +3054,8 @@
"integrationtestcommon": {
"type": "Project",
"dependencies": {
"Common": "[2023.10.2, )",
"Identity": "[2023.10.2, )",
"Common": "[2023.10.3, )",
"Identity": "[2023.10.3, )",
"Microsoft.AspNetCore.Mvc.Testing": "[6.0.5, )",
"Microsoft.Extensions.Configuration": "[6.0.1, )"
}
@ -3087,16 +3063,16 @@
"scim": {
"type": "Project",
"dependencies": {
"Core": "[2023.10.2, )",
"SharedWeb": "[2023.10.2, )"
"Core": "[2023.10.3, )",
"SharedWeb": "[2023.10.3, )"
}
},
"sharedweb": {
"type": "Project",
"dependencies": {
"Core": "[2023.10.2, )",
"Infrastructure.Dapper": "[2023.10.2, )",
"Infrastructure.EntityFramework": "[2023.10.2, )"
"Core": "[2023.10.3, )",
"Infrastructure.Dapper": "[2023.10.3, )",
"Infrastructure.EntityFramework": "[2023.10.3, )"
}
}
}

View File

@ -270,6 +270,24 @@
"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": {
"type": "Transitive",
"resolved": "2.1.1",
@ -314,49 +332,8 @@
},
"IdentityModel": {
"type": "Transitive",
"resolved": "4.4.0",
"contentHash": "b18wrIx5wnZlMxAX7oVsE+nDtAJ4hajYlH0xPlaRvo4r/fz08K6pPeZvbiqS9nfNbzfIgLFmNX+FL9qR9ZR5PA==",
"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"
}
"resolved": "6.0.0",
"contentHash": "eVHCR7a6m/dm5RFcBzE3qs/Jg5j9R5Rjpu8aTOv9e4AFvaQtBXb5ah7kmwU+YwA0ufRwz4wf1hnIvsD2hSnI4g=="
},
"Kralizek.AutoFixture.Extensions.MockHttp": {
"type": "Transitive",
@ -457,10 +434,10 @@
},
"Microsoft.AspNetCore.Authentication.OpenIdConnect": {
"type": "Transitive",
"resolved": "3.1.0",
"contentHash": "O1cAQYUTU8EfRqwc5/rfTns4E4hKlFlg59fuKRrST+PzsxI6H07KqRN/JjdYhAuVYxF8jPnIGbj+zuc5paOWUw==",
"resolved": "6.0.0",
"contentHash": "cJxdro36spFzk/K2OFCddM6vZ+yoj6ug8mTFRH3Gdv1Pul/buSuCtfb/FSCp31UmS5S4C1315dU7wX3ErLFuDg==",
"dependencies": {
"Microsoft.IdentityModel.Protocols.OpenIdConnect": "5.5.0"
"Microsoft.IdentityModel.Protocols.OpenIdConnect": "6.10.0"
}
},
"Microsoft.AspNetCore.Cryptography.Internal": {
@ -493,8 +470,8 @@
},
"Microsoft.AspNetCore.DataProtection.Abstractions": {
"type": "Transitive",
"resolved": "3.1.32",
"contentHash": "MPL4iVyiaRxnOUY5VATHjvhDWaAEFb77KFiUxVRklv3Z3v+STofUr1UG/aCt1O9cgN7FVTDaC5A7U+zsLub8Xg=="
"resolved": "6.0.0",
"contentHash": "Z/UU4NEBm5UgNufJmw+j5baW26ytCOIZ0G7sZocPaOzsUeBon1bkM3lSMNZQG2GmDjAIVP2XMSODf2jzSGbibw=="
},
"Microsoft.Azure.Amqp": {
"type": "Transitive",
@ -2850,7 +2827,7 @@
"dependencies": {
"AutoFixture.AutoNSubstitute": "[4.17.0, )",
"AutoFixture.Xunit2": "[4.17.0, )",
"Core": "[2023.10.2, )",
"Core": "[2023.10.3, )",
"Kralizek.AutoFixture.Extensions.MockHttp": "[1.2.0, )",
"Microsoft.NET.Test.Sdk": "[17.1.0, )",
"NSubstitute": "[4.3.0, )",
@ -2872,10 +2849,9 @@
"BitPay.Light": "[1.0.1907, )",
"Braintree": "[5.19.0, )",
"DnsClient": "[1.7.0, )",
"Duende.IdentityServer": "[6.0.4, )",
"Fido2.AspNet": "[3.0.1, )",
"Handlebars.Net": "[2.1.2, )",
"IdentityServer4": "[4.1.2, )",
"IdentityServer4.AccessTokenValidation": "[3.0.1, )",
"LaunchDarkly.ServerSdk": "[8.0.0, )",
"MailKit": "[4.2.0, )",
"Microsoft.AspNetCore.Authentication.JwtBearer": "[6.0.4, )",
@ -2903,7 +2879,7 @@
"infrastructure.dapper": {
"type": "Project",
"dependencies": {
"Core": "[2023.10.2, )",
"Core": "[2023.10.3, )",
"Dapper": "[2.0.123, )"
}
},
@ -2911,7 +2887,7 @@
"type": "Project",
"dependencies": {
"AutoMapper.Extensions.Microsoft.DependencyInjection": "[12.0.1, )",
"Core": "[2023.10.2, )",
"Core": "[2023.10.3, )",
"Microsoft.EntityFrameworkCore.Relational": "[7.0.5, )",
"Microsoft.EntityFrameworkCore.SqlServer": "[7.0.5, )",
"Microsoft.EntityFrameworkCore.Sqlite": "[7.0.5, )",
@ -2923,16 +2899,16 @@
"scim": {
"type": "Project",
"dependencies": {
"Core": "[2023.10.2, )",
"SharedWeb": "[2023.10.2, )"
"Core": "[2023.10.3, )",
"SharedWeb": "[2023.10.3, )"
}
},
"sharedweb": {
"type": "Project",
"dependencies": {
"Core": "[2023.10.2, )",
"Infrastructure.Dapper": "[2023.10.2, )",
"Infrastructure.EntityFramework": "[2023.10.2, )"
"Core": "[2023.10.3, )",
"Infrastructure.Dapper": "[2023.10.3, )",
"Infrastructure.EntityFramework": "[2023.10.3, )"
}
}
}

View File

@ -192,6 +192,24 @@
"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": {
"type": "Transitive",
"resolved": "3.0.1",
@ -233,49 +251,8 @@
},
"IdentityModel": {
"type": "Transitive",
"resolved": "4.4.0",
"contentHash": "b18wrIx5wnZlMxAX7oVsE+nDtAJ4hajYlH0xPlaRvo4r/fz08K6pPeZvbiqS9nfNbzfIgLFmNX+FL9qR9ZR5PA==",
"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"
}
"resolved": "6.0.0",
"contentHash": "eVHCR7a6m/dm5RFcBzE3qs/Jg5j9R5Rjpu8aTOv9e4AFvaQtBXb5ah7kmwU+YwA0ufRwz4wf1hnIvsD2hSnI4g=="
},
"LaunchDarkly.Cache": {
"type": "Transitive",
@ -353,10 +330,10 @@
},
"Microsoft.AspNetCore.Authentication.OpenIdConnect": {
"type": "Transitive",
"resolved": "3.1.0",
"contentHash": "O1cAQYUTU8EfRqwc5/rfTns4E4hKlFlg59fuKRrST+PzsxI6H07KqRN/JjdYhAuVYxF8jPnIGbj+zuc5paOWUw==",
"resolved": "6.0.0",
"contentHash": "cJxdro36spFzk/K2OFCddM6vZ+yoj6ug8mTFRH3Gdv1Pul/buSuCtfb/FSCp31UmS5S4C1315dU7wX3ErLFuDg==",
"dependencies": {
"Microsoft.IdentityModel.Protocols.OpenIdConnect": "5.5.0"
"Microsoft.IdentityModel.Protocols.OpenIdConnect": "6.10.0"
}
},
"Microsoft.AspNetCore.Cryptography.Internal": {
@ -389,8 +366,8 @@
},
"Microsoft.AspNetCore.DataProtection.Abstractions": {
"type": "Transitive",
"resolved": "3.1.32",
"contentHash": "MPL4iVyiaRxnOUY5VATHjvhDWaAEFb77KFiUxVRklv3Z3v+STofUr1UG/aCt1O9cgN7FVTDaC5A7U+zsLub8Xg=="
"resolved": "6.0.0",
"contentHash": "Z/UU4NEBm5UgNufJmw+j5baW26ytCOIZ0G7sZocPaOzsUeBon1bkM3lSMNZQG2GmDjAIVP2XMSODf2jzSGbibw=="
},
"Microsoft.Azure.Amqp": {
"type": "Transitive",
@ -2557,10 +2534,9 @@
"BitPay.Light": "[1.0.1907, )",
"Braintree": "[5.19.0, )",
"DnsClient": "[1.7.0, )",
"Duende.IdentityServer": "[6.0.4, )",
"Fido2.AspNet": "[3.0.1, )",
"Handlebars.Net": "[2.1.2, )",
"IdentityServer4": "[4.1.2, )",
"IdentityServer4.AccessTokenValidation": "[3.0.1, )",
"LaunchDarkly.ServerSdk": "[8.0.0, )",
"MailKit": "[4.2.0, )",
"Microsoft.AspNetCore.Authentication.JwtBearer": "[6.0.4, )",

View File

@ -82,7 +82,11 @@
<label asp-for="PlanType"></label>
@{
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
{
Value = ((int)e).ToString(),

View File

@ -223,6 +223,24 @@
"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": {
"type": "Transitive",
"resolved": "3.0.1",
@ -259,49 +277,8 @@
},
"IdentityModel": {
"type": "Transitive",
"resolved": "4.4.0",
"contentHash": "b18wrIx5wnZlMxAX7oVsE+nDtAJ4hajYlH0xPlaRvo4r/fz08K6pPeZvbiqS9nfNbzfIgLFmNX+FL9qR9ZR5PA==",
"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"
}
"resolved": "6.0.0",
"contentHash": "eVHCR7a6m/dm5RFcBzE3qs/Jg5j9R5Rjpu8aTOv9e4AFvaQtBXb5ah7kmwU+YwA0ufRwz4wf1hnIvsD2hSnI4g=="
},
"LaunchDarkly.Cache": {
"type": "Transitive",
@ -393,10 +370,10 @@
},
"Microsoft.AspNetCore.Authentication.OpenIdConnect": {
"type": "Transitive",
"resolved": "3.1.0",
"contentHash": "O1cAQYUTU8EfRqwc5/rfTns4E4hKlFlg59fuKRrST+PzsxI6H07KqRN/JjdYhAuVYxF8jPnIGbj+zuc5paOWUw==",
"resolved": "6.0.0",
"contentHash": "cJxdro36spFzk/K2OFCddM6vZ+yoj6ug8mTFRH3Gdv1Pul/buSuCtfb/FSCp31UmS5S4C1315dU7wX3ErLFuDg==",
"dependencies": {
"Microsoft.IdentityModel.Protocols.OpenIdConnect": "5.5.0"
"Microsoft.IdentityModel.Protocols.OpenIdConnect": "6.10.0"
}
},
"Microsoft.AspNetCore.Cryptography.Internal": {
@ -429,8 +406,8 @@
},
"Microsoft.AspNetCore.DataProtection.Abstractions": {
"type": "Transitive",
"resolved": "3.1.32",
"contentHash": "MPL4iVyiaRxnOUY5VATHjvhDWaAEFb77KFiUxVRklv3Z3v+STofUr1UG/aCt1O9cgN7FVTDaC5A7U+zsLub8Xg=="
"resolved": "6.0.0",
"contentHash": "Z/UU4NEBm5UgNufJmw+j5baW26ytCOIZ0G7sZocPaOzsUeBon1bkM3lSMNZQG2GmDjAIVP2XMSODf2jzSGbibw=="
},
"Microsoft.Azure.Amqp": {
"type": "Transitive",
@ -2808,15 +2785,15 @@
"commercial.core": {
"type": "Project",
"dependencies": {
"Core": "[2023.10.2, )"
"Core": "[2023.10.3, )"
}
},
"commercial.infrastructure.entityframework": {
"type": "Project",
"dependencies": {
"AutoMapper.Extensions.Microsoft.DependencyInjection": "[12.0.1, )",
"Core": "[2023.10.2, )",
"Infrastructure.EntityFramework": "[2023.10.2, )"
"Core": "[2023.10.3, )",
"Infrastructure.EntityFramework": "[2023.10.3, )"
}
},
"core": {
@ -2834,10 +2811,9 @@
"BitPay.Light": "[1.0.1907, )",
"Braintree": "[5.19.0, )",
"DnsClient": "[1.7.0, )",
"Duende.IdentityServer": "[6.0.4, )",
"Fido2.AspNet": "[3.0.1, )",
"Handlebars.Net": "[2.1.2, )",
"IdentityServer4": "[4.1.2, )",
"IdentityServer4.AccessTokenValidation": "[3.0.1, )",
"LaunchDarkly.ServerSdk": "[8.0.0, )",
"MailKit": "[4.2.0, )",
"Microsoft.AspNetCore.Authentication.JwtBearer": "[6.0.4, )",
@ -2865,7 +2841,7 @@
"infrastructure.dapper": {
"type": "Project",
"dependencies": {
"Core": "[2023.10.2, )",
"Core": "[2023.10.3, )",
"Dapper": "[2.0.123, )"
}
},
@ -2873,7 +2849,7 @@
"type": "Project",
"dependencies": {
"AutoMapper.Extensions.Microsoft.DependencyInjection": "[12.0.1, )",
"Core": "[2023.10.2, )",
"Core": "[2023.10.3, )",
"Microsoft.EntityFrameworkCore.Relational": "[7.0.5, )",
"Microsoft.EntityFrameworkCore.SqlServer": "[7.0.5, )",
"Microsoft.EntityFrameworkCore.Sqlite": "[7.0.5, )",
@ -2885,7 +2861,7 @@
"migrator": {
"type": "Project",
"dependencies": {
"Core": "[2023.10.2, )",
"Core": "[2023.10.3, )",
"Microsoft.Extensions.Logging": "[6.0.0, )",
"dbup-sqlserver": "[5.0.8, )"
}
@ -2893,30 +2869,30 @@
"mysqlmigrations": {
"type": "Project",
"dependencies": {
"Core": "[2023.10.2, )",
"Infrastructure.EntityFramework": "[2023.10.2, )"
"Core": "[2023.10.3, )",
"Infrastructure.EntityFramework": "[2023.10.3, )"
}
},
"postgresmigrations": {
"type": "Project",
"dependencies": {
"Core": "[2023.10.2, )",
"Infrastructure.EntityFramework": "[2023.10.2, )"
"Core": "[2023.10.3, )",
"Infrastructure.EntityFramework": "[2023.10.3, )"
}
},
"sharedweb": {
"type": "Project",
"dependencies": {
"Core": "[2023.10.2, )",
"Infrastructure.Dapper": "[2023.10.2, )",
"Infrastructure.EntityFramework": "[2023.10.2, )"
"Core": "[2023.10.3, )",
"Infrastructure.Dapper": "[2023.10.3, )",
"Infrastructure.EntityFramework": "[2023.10.3, )"
}
},
"sqlitemigrations": {
"type": "Project",
"dependencies": {
"Core": "[2023.10.2, )",
"Infrastructure.EntityFramework": "[2023.10.2, )"
"Core": "[2023.10.3, )",
"Infrastructure.EntityFramework": "[2023.10.3, )"
}
}
}

View File

@ -5,6 +5,8 @@ using Bit.Api.Models.Response;
using Bit.Api.Utilities;
using Bit.Api.Vault.AuthorizationHandlers.OrganizationUsers;
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.Repositories;
using Bit.Core.Context;
@ -12,7 +14,6 @@ using Bit.Core.Enums;
using Bit.Core.Exceptions;
using Bit.Core.Models.Business;
using Bit.Core.Models.Data.Organizations.OrganizationUsers;
using Bit.Core.Models.Data.Organizations.Policies;
using Bit.Core.OrganizationFeatures.OrganizationSubscriptions.Interface;
using Bit.Core.OrganizationFeatures.OrganizationUsers.Interfaces;
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.Response;
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.Repositories;
using Bit.Core.Auth.Enums;
@ -20,7 +22,6 @@ using Bit.Core.Context;
using Bit.Core.Enums;
using Bit.Core.Exceptions;
using Bit.Core.Models.Business;
using Bit.Core.Models.Data.Organizations.Policies;
using Bit.Core.OrganizationFeatures.OrganizationLicenses.Interfaces;
using Bit.Core.OrganizationFeatures.OrganizationSubscriptions.Interface;
using Bit.Core.Repositories;
@ -794,7 +795,7 @@ public class OrganizationsController : Controller
throw new NotFoundException();
}
await _organizationService.UpdateAsync(model.ToOrganization(organization));
await _organizationService.UpdateAsync(model.ToOrganization(organization), eventType: EventType.Organization_CollectionManagement_Updated);
return new OrganizationResponseModel(organization);
}

View File

@ -1,10 +1,13 @@
using Bit.Api.AdminConsole.Models.Request;
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.Context;
using Bit.Core.Enums;
using Bit.Core.Exceptions;
using Bit.Core.Models.Api.Response;
using Bit.Core.Repositories;
using Bit.Core.Services;
using Bit.Core.Settings;

View File

@ -1,7 +1,7 @@
using System.ComponentModel.DataAnnotations;
using System.Text.Json;
using Bit.Core.Entities;
using Bit.Core.Enums;
using Bit.Core.AdminConsole.Entities;
using Bit.Core.AdminConsole.Enums;
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.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.Enums;
using Bit.Core.Repositories;
using Bit.Core.Services;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;

View File

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

View File

@ -1,8 +1,8 @@
using System.ComponentModel.DataAnnotations;
using System.Text.Json;
using Bit.Api.Models.Public.Response;
using Bit.Core.Entities;
using Bit.Core.Enums;
using Bit.Core.AdminConsole.Entities;
using Bit.Core.AdminConsole.Enums;
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.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.Entities;
using Bit.Core.Exceptions;
using Bit.Core.Models.Api.Response;
using Bit.Core.Repositories;
using Bit.Core.Services;
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.Models.Response;
using Bit.Core;
using Bit.Core.AdminConsole.Enums;
using Bit.Core.AdminConsole.Services;
using Bit.Core.Auth.Models.Business.Tokenables;
using Bit.Core.Auth.Repositories;
using Bit.Core.Enums;
using Bit.Core.Exceptions;
using Bit.Core.Services;
using Bit.Core.Tokens;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,9 +1,10 @@
using Bit.Api.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.Entities;
using Bit.Core.Models.Api;
using Bit.Core.Models.Api.Response;
using Bit.Core.Models.Data;
using Bit.Core.Models.Data.Organizations.OrganizationUsers;
using Bit.Core.Settings;

View File

@ -307,6 +307,24 @@
"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": {
"type": "Transitive",
"resolved": "3.0.1",
@ -343,49 +361,8 @@
},
"IdentityModel": {
"type": "Transitive",
"resolved": "4.4.0",
"contentHash": "b18wrIx5wnZlMxAX7oVsE+nDtAJ4hajYlH0xPlaRvo4r/fz08K6pPeZvbiqS9nfNbzfIgLFmNX+FL9qR9ZR5PA==",
"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"
}
"resolved": "6.0.0",
"contentHash": "eVHCR7a6m/dm5RFcBzE3qs/Jg5j9R5Rjpu8aTOv9e4AFvaQtBXb5ah7kmwU+YwA0ufRwz4wf1hnIvsD2hSnI4g=="
},
"LaunchDarkly.Cache": {
"type": "Transitive",
@ -477,10 +454,10 @@
},
"Microsoft.AspNetCore.Authentication.OpenIdConnect": {
"type": "Transitive",
"resolved": "3.1.0",
"contentHash": "O1cAQYUTU8EfRqwc5/rfTns4E4hKlFlg59fuKRrST+PzsxI6H07KqRN/JjdYhAuVYxF8jPnIGbj+zuc5paOWUw==",
"resolved": "6.0.0",
"contentHash": "cJxdro36spFzk/K2OFCddM6vZ+yoj6ug8mTFRH3Gdv1Pul/buSuCtfb/FSCp31UmS5S4C1315dU7wX3ErLFuDg==",
"dependencies": {
"Microsoft.IdentityModel.Protocols.OpenIdConnect": "5.5.0"
"Microsoft.IdentityModel.Protocols.OpenIdConnect": "6.10.0"
}
},
"Microsoft.AspNetCore.Cryptography.Internal": {
@ -513,8 +490,8 @@
},
"Microsoft.AspNetCore.DataProtection.Abstractions": {
"type": "Transitive",
"resolved": "3.1.32",
"contentHash": "MPL4iVyiaRxnOUY5VATHjvhDWaAEFb77KFiUxVRklv3Z3v+STofUr1UG/aCt1O9cgN7FVTDaC5A7U+zsLub8Xg=="
"resolved": "6.0.0",
"contentHash": "Z/UU4NEBm5UgNufJmw+j5baW26ytCOIZ0G7sZocPaOzsUeBon1bkM3lSMNZQG2GmDjAIVP2XMSODf2jzSGbibw=="
},
"Microsoft.Azure.Amqp": {
"type": "Transitive",
@ -2788,15 +2765,15 @@
"commercial.core": {
"type": "Project",
"dependencies": {
"Core": "[2023.10.2, )"
"Core": "[2023.10.3, )"
}
},
"commercial.infrastructure.entityframework": {
"type": "Project",
"dependencies": {
"AutoMapper.Extensions.Microsoft.DependencyInjection": "[12.0.1, )",
"Core": "[2023.10.2, )",
"Infrastructure.EntityFramework": "[2023.10.2, )"
"Core": "[2023.10.3, )",
"Infrastructure.EntityFramework": "[2023.10.3, )"
}
},
"core": {
@ -2814,10 +2791,9 @@
"BitPay.Light": "[1.0.1907, )",
"Braintree": "[5.19.0, )",
"DnsClient": "[1.7.0, )",
"Duende.IdentityServer": "[6.0.4, )",
"Fido2.AspNet": "[3.0.1, )",
"Handlebars.Net": "[2.1.2, )",
"IdentityServer4": "[4.1.2, )",
"IdentityServer4.AccessTokenValidation": "[3.0.1, )",
"LaunchDarkly.ServerSdk": "[8.0.0, )",
"MailKit": "[4.2.0, )",
"Microsoft.AspNetCore.Authentication.JwtBearer": "[6.0.4, )",
@ -2845,7 +2821,7 @@
"infrastructure.dapper": {
"type": "Project",
"dependencies": {
"Core": "[2023.10.2, )",
"Core": "[2023.10.3, )",
"Dapper": "[2.0.123, )"
}
},
@ -2853,7 +2829,7 @@
"type": "Project",
"dependencies": {
"AutoMapper.Extensions.Microsoft.DependencyInjection": "[12.0.1, )",
"Core": "[2023.10.2, )",
"Core": "[2023.10.3, )",
"Microsoft.EntityFrameworkCore.Relational": "[7.0.5, )",
"Microsoft.EntityFrameworkCore.SqlServer": "[7.0.5, )",
"Microsoft.EntityFrameworkCore.Sqlite": "[7.0.5, )",
@ -2865,9 +2841,9 @@
"sharedweb": {
"type": "Project",
"dependencies": {
"Core": "[2023.10.2, )",
"Infrastructure.Dapper": "[2023.10.2, )",
"Infrastructure.EntityFramework": "[2023.10.2, )"
"Core": "[2023.10.3, )",
"Infrastructure.Dapper": "[2023.10.3, )",
"Infrastructure.EntityFramework": "[2023.10.3, )"
}
}
}

View File

@ -264,9 +264,16 @@ public class StripeController : Controller
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)
{

View File

@ -184,6 +184,24 @@
"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": {
"type": "Transitive",
"resolved": "3.0.1",
@ -220,49 +238,8 @@
},
"IdentityModel": {
"type": "Transitive",
"resolved": "4.4.0",
"contentHash": "b18wrIx5wnZlMxAX7oVsE+nDtAJ4hajYlH0xPlaRvo4r/fz08K6pPeZvbiqS9nfNbzfIgLFmNX+FL9qR9ZR5PA==",
"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"
}
"resolved": "6.0.0",
"contentHash": "eVHCR7a6m/dm5RFcBzE3qs/Jg5j9R5Rjpu8aTOv9e4AFvaQtBXb5ah7kmwU+YwA0ufRwz4wf1hnIvsD2hSnI4g=="
},
"LaunchDarkly.Cache": {
"type": "Transitive",
@ -354,10 +331,10 @@
},
"Microsoft.AspNetCore.Authentication.OpenIdConnect": {
"type": "Transitive",
"resolved": "3.1.0",
"contentHash": "O1cAQYUTU8EfRqwc5/rfTns4E4hKlFlg59fuKRrST+PzsxI6H07KqRN/JjdYhAuVYxF8jPnIGbj+zuc5paOWUw==",
"resolved": "6.0.0",
"contentHash": "cJxdro36spFzk/K2OFCddM6vZ+yoj6ug8mTFRH3Gdv1Pul/buSuCtfb/FSCp31UmS5S4C1315dU7wX3ErLFuDg==",
"dependencies": {
"Microsoft.IdentityModel.Protocols.OpenIdConnect": "5.5.0"
"Microsoft.IdentityModel.Protocols.OpenIdConnect": "6.10.0"
}
},
"Microsoft.AspNetCore.Cryptography.Internal": {
@ -390,8 +367,8 @@
},
"Microsoft.AspNetCore.DataProtection.Abstractions": {
"type": "Transitive",
"resolved": "3.1.32",
"contentHash": "MPL4iVyiaRxnOUY5VATHjvhDWaAEFb77KFiUxVRklv3Z3v+STofUr1UG/aCt1O9cgN7FVTDaC5A7U+zsLub8Xg=="
"resolved": "6.0.0",
"contentHash": "Z/UU4NEBm5UgNufJmw+j5baW26ytCOIZ0G7sZocPaOzsUeBon1bkM3lSMNZQG2GmDjAIVP2XMSODf2jzSGbibw=="
},
"Microsoft.Azure.Amqp": {
"type": "Transitive",
@ -2617,10 +2594,9 @@
"BitPay.Light": "[1.0.1907, )",
"Braintree": "[5.19.0, )",
"DnsClient": "[1.7.0, )",
"Duende.IdentityServer": "[6.0.4, )",
"Fido2.AspNet": "[3.0.1, )",
"Handlebars.Net": "[2.1.2, )",
"IdentityServer4": "[4.1.2, )",
"IdentityServer4.AccessTokenValidation": "[3.0.1, )",
"LaunchDarkly.ServerSdk": "[8.0.0, )",
"MailKit": "[4.2.0, )",
"Microsoft.AspNetCore.Authentication.JwtBearer": "[6.0.4, )",
@ -2648,7 +2624,7 @@
"infrastructure.dapper": {
"type": "Project",
"dependencies": {
"Core": "[2023.10.2, )",
"Core": "[2023.10.3, )",
"Dapper": "[2.0.123, )"
}
},
@ -2656,7 +2632,7 @@
"type": "Project",
"dependencies": {
"AutoMapper.Extensions.Microsoft.DependencyInjection": "[12.0.1, )",
"Core": "[2023.10.2, )",
"Core": "[2023.10.3, )",
"Microsoft.EntityFrameworkCore.Relational": "[7.0.5, )",
"Microsoft.EntityFrameworkCore.SqlServer": "[7.0.5, )",
"Microsoft.EntityFrameworkCore.Sqlite": "[7.0.5, )",
@ -2668,9 +2644,9 @@
"sharedweb": {
"type": "Project",
"dependencies": {
"Core": "[2023.10.2, )",
"Infrastructure.Dapper": "[2023.10.2, )",
"Infrastructure.EntityFramework": "[2023.10.2, )"
"Core": "[2023.10.3, )",
"Infrastructure.Dapper": "[2023.10.3, )",
"Infrastructure.EntityFramework": "[2023.10.3, )"
}
}
}

View File

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

View File

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

View File

@ -1,8 +1,9 @@
using System.Text.Json;
using Bit.Core.Entities;
using Bit.Core.Enums;
using Bit.Core.AdminConsole.Entities;
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
{

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
{

View File

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

View File

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

View File

@ -1,7 +1,8 @@
using Bit.Core.Entities;
using Bit.Core.Enums;
using Bit.Core.AdminConsole.Entities;
using Bit.Core.AdminConsole.Enums;
using Bit.Core.Repositories;
namespace Bit.Core.Repositories;
namespace Bit.Core.AdminConsole.Repositories;
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.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
{

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

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>
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>
/// Gets or sets information regarding this users trusted device decryption setup.
/// </summary>
@ -29,6 +35,20 @@ public class UserDecryptionOptions : ResponseModel
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 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.Models.Data;
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.Models;
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.Repositories;
using Bit.Core.Entities;
using Bit.Core.Enums;
using Bit.Core.Exceptions;
using Bit.Core.Models.Data.Organizations.Policies;
using Bit.Core.Repositories;
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";
/// <summary>
/// When you set the ProrationBehavior to create_prorations,
/// Stripe will automatically create prorations for any changes made to the subscription,
/// such as changing the plan, adding or removing quantities, or applying discounts.
/// Used by IdentityServer to identify our own provider.
/// </summary>
public const string CreateProrations = "create_prorations";
/// <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 const string IdentityProvider = "bitwarden";
}
public static class TokenPurposes
@ -57,6 +48,7 @@ public static class FeatureFlagKeys
public const string PasswordlessLogin = "passwordless-login";
public const string TrustedDeviceEncryption = "trusted-device-encryption";
public const string Fido2VaultCredentials = "fido2-vault-credentials";
public const string VaultOnboarding = "vault-onboarding";
public const string AutofillV2 = "autofill-v2";
public const string BrowserFilelessImport = "browser-fileless-import";
public const string FlexibleCollections = "flexible-collections";

View File

@ -31,7 +31,6 @@
<PackageReference Include="DnsClient" Version="1.7.0" />
<PackageReference Include="Fido2.AspNet" Version="3.0.1" />
<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="Microsoft.AspNetCore.Authentication.JwtBearer" Version="6.0.4" />
<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.File" Version="2.0.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="Serilog.Sinks.AzureCosmosDB" Version="2.0.0" />
<PackageReference Include="Serilog.Sinks.SyslogMessages" Version="2.0.6" />

View File

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

View File

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

View File

@ -1,5 +1,5 @@
using Bit.Core.Settings;
using IdentityServer4.Configuration;
using Duende.IdentityServer.Configuration;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Http;
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;

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

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.Enums;
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.Auth.Enums;
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.Enums;
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.Models.Data;
using Bit.Core.Models.Data.Organizations.OrganizationUsers;

View File

@ -27,7 +27,7 @@ public interface IOrganizationService
Task DisableAsync(Guid organizationId, DateTime? expirationDate);
Task UpdateExpirationDateAsync(Guid organizationId, DateTime? expirationDate);
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 DisableTwoFactorProviderAsync(Organization organization, TwoFactorProviderType type);
Task<List<OrganizationUser>> InviteUsersAsync(Guid organizationId, Guid? invitingUserId,

View File

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

View File

@ -1,4 +1,5 @@
using System.Security.Claims;
using Bit.Core.Auth.Entities;
using Bit.Core.Auth.Enums;
using Bit.Core.Auth.Models;
using Bit.Core.Entities;
@ -29,8 +30,8 @@ public interface IUserService
Task<bool> CompleteWebAuthRegistrationAsync(User user, int value, string name, AuthenticatorAttestationRawResponse attestationResponse);
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<AssertionOptions> StartWebAuthnLoginAssertionAsync(User user);
Task<string> CompleteWebAuthLoginAssertionAsync(AuthenticatorAssertionRawResponse assertionResponse, User user);
AssertionOptions StartWebAuthnLoginAssertion();
Task<(User, WebAuthnCredential)> CompleteWebAuthLoginAssertionAsync(AssertionOptions options, AuthenticatorAssertionRawResponse assertionResponse);
Task SendEmailVerificationAsync(User user);
Task<IdentityResult> ConfirmEmailAsync(User user, string token);
Task InitiateEmailChangeAsync(User user, string newEmail);

View File

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

View File

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

View File

@ -7,7 +7,6 @@ using Bit.Core.Models.Business;
using Bit.Core.Repositories;
using Bit.Core.Settings;
using Microsoft.Extensions.Logging;
using Stripe;
using StaticStore = Bit.Core.Models.StaticStore;
using TaxRate = Bit.Core.Entities.TaxRate;
@ -751,14 +750,16 @@ public class StripePaymentService : IPaymentService
prorationDate ??= DateTime.UtcNow;
var collectionMethod = sub.CollectionMethod;
var daysUntilDue = sub.DaysUntilDue;
var chargeNow = collectionMethod == "charge_automatically";
var updatedItemOptions = subscriptionUpdate.UpgradeItemsOptions(sub);
var subUpdateOptions = new Stripe.SubscriptionUpdateOptions
{
Items = updatedItemOptions,
ProrationBehavior = Constants.CreateProrations,
ProrationBehavior = "always_invoice",
DaysUntilDue = daysUntilDue ?? 1,
CollectionMethod = "send_invoice"
CollectionMethod = "send_invoice",
ProrationDate = prorationDate,
};
if (!subscriptionUpdate.UpdateNeeded(sub))
@ -792,50 +793,66 @@ public class StripePaymentService : IPaymentService
string paymentIntentClientSecret = null;
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 invoice =
await _stripeAdapter.InvoiceGetAsync(subResponse?.LatestInvoiceId, new Stripe.InvoiceGetOptions());
var invoice = await _stripeAdapter.InvoiceGetAsync(subResponse?.LatestInvoiceId, new Stripe.InvoiceGetOptions());
if (invoice == null)
{
throw new BadRequestException("Unable to locate draft invoice for subscription update.");
}
}
catch (Exception e)
{
// Need to revert the subscription
await _stripeAdapter.SubscriptionUpdateAsync(sub.Id, new Stripe.SubscriptionUpdateOptions
if (invoice.AmountDue > 0 && updatedItemOptions.Any(i => i.Quantity > 0))
{
Items = subscriptionUpdate.RevertItemsOptions(sub),
// This proration behavior prevents a false "credit" from
// being applied forward to the next month's invoice
ProrationBehavior = "none",
CollectionMethod = collectionMethod,
DaysUntilDue = daysUntilDue,
});
throw;
try
{
if (chargeNow)
{
paymentIntentClientSecret = await PayInvoiceAfterSubscriptionChangeAsync(
storableSubscriber, invoice);
}
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
await _stripeAdapter.SubscriptionUpdateAsync(sub.Id, new Stripe.SubscriptionUpdateOptions
{
Items = subscriptionUpdate.RevertItemsOptions(sub),
// This proration behavior prevents a false "credit" from
// being applied forward to the next month's invoice
ProrationBehavior = "none",
CollectionMethod = collectionMethod,
DaysUntilDue = daysUntilDue,
});
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
{
// Change back the subscription collection method and/or days until due
if (collectionMethod != "send_invoice" || daysUntilDue == null)
{
await _stripeAdapter.SubscriptionUpdateAsync(sub.Id,
new Stripe.SubscriptionUpdateOptions
{
CollectionMethod = collectionMethod,
DaysUntilDue = daysUntilDue,
});
await _stripeAdapter.SubscriptionUpdateAsync(sub.Id, new Stripe.SubscriptionUpdateOptions
{
CollectionMethod = collectionMethod,
DaysUntilDue = daysUntilDue,
});
}
}
@ -918,7 +935,6 @@ public class StripePaymentService : IPaymentService
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)
{
var customerOptions = new Stripe.CustomerGetOptions();
@ -1088,310 +1104,6 @@ public class StripePaymentService : IPaymentService
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,
bool skipInAppPurchaseCheck = false)
{

View File

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

View File

@ -1,29 +1,125 @@
using System.ComponentModel.DataAnnotations;
#nullable enable
using System.ComponentModel.DataAnnotations;
using Bit.Core.Entities;
using Bit.Core.Tools.Enums;
using Bit.Core.Utilities;
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>
{
/// <summary>
/// Uniquely identifies this send.
/// </summary>
public Guid Id { get; set; }
/// <summary>
/// Identifies the user that created this send.
/// </summary>
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; }
/// <summary>
/// Describes the data being sent. This field determines how
/// the <see cref="Data"/> field is interpreted.
/// </summary>
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)]
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; }
/// <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; }
/// <summary>
/// The date this send was created.
/// </summary>
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;
/// <summary>
/// The date this send becomes unavailable to API callers.
/// </summary>
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; }
/// <summary>
/// When this is true the send is not available to API callers,
/// unless they're the creator.
/// </summary>
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; }
/// <summary>
/// Generates the send's <see cref="Id" />
/// </summary>
public void SetNewId()
{
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.Enums;
using Bit.Core.Tools.Entities;
@ -6,10 +8,23 @@ using Bit.Core.Tools.Enums;
namespace Bit.Core.Tools.Models.Business;
/// <summary>
/// Product support monitoring.
/// </summary>
/// <remarks>
/// Do not store secrets in this type.
/// </remarks>
public class ReferenceEvent
{
/// <summary>
/// Instantiates a <see cref="ReferenceEvent"/>.
/// </summary>
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)
{
Type = type;
@ -26,48 +41,197 @@ public class ReferenceEvent
}
}
/// <summary>
/// Monitored event type.
/// </summary>
[JsonConverter(typeof(JsonStringEnumConverter))]
public ReferenceEventType Type { get; set; }
/// <summary>
/// The kind of entity that created the event.
/// </summary>
[JsonConverter(typeof(JsonStringEnumConverter))]
public ReferenceEventSource Source { get; set; }
/// <inheritdoc cref="IReferenceable.Id"/>
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;
/// <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; }
/// <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 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 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; }
/// <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; }
/// <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; }
/// <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; }
/// <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))]
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; }
/// <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; }
/// <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 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 string ClientId { get; set; }
public Version ClientVersion { get; set; }
/// <summary>
/// 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
{
/// <summary>
/// Instantiates a <see cref="SendData"/>.
/// </summary>
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;
Notes = notes;
}
public string Name { get; set; }
public string Notes { get; set; }
/// <summary>
/// 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;
/// <summary>
/// A file secret being sent.
/// </summary>
public class SendFileData : SendData
{
/// <summary>
/// Instantiates a <see cref="SendFileData"/>.
/// </summary>
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)
{
FileName = fileName;
}
// We serialize Size as a string since JSON (or Javascript) doesn't support full precision for long numbers
[JsonNumberHandling(JsonNumberHandling.WriteAsString | JsonNumberHandling.AllowReadingFromString)]
/// <summary>
/// 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 string Id { get; set; }
public string FileName { get; set; }
/// <summary>
/// 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;
}

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
{
/// <summary>
/// Instantiates a <see cref="SendTextData"/>.
/// </summary>
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)
{
Text = text;
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; }
}

View File

@ -1,10 +1,36 @@
using Bit.Core.Repositories;
#nullable enable
using Bit.Core.Repositories;
using Bit.Core.Tools.Entities;
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>
{
/// <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);
/// <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);
}

View File

@ -1,9 +1,11 @@
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.Entities;
using Bit.Core.Enums;
using Bit.Core.Exceptions;
using Bit.Core.Models.Data.Organizations.Policies;
using Bit.Core.Repositories;
using Bit.Core.Services;
using Bit.Core.Settings;

View File

@ -12,6 +12,7 @@ public class CipherLoginFido2CredentialData
public string RpId { get; set; }
public string RpName { get; set; }
public string UserHandle { get; set; }
public string UserName { get; set; }
public string UserDisplayName { get; set; }
public string Counter { 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 CreateAsync(IEnumerable<Cipher> ciphers, IEnumerable<Folder> folders);
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 SoftDeleteByIdsOrganizationIdAsync(IEnumerable<Guid> ids, Guid organizationId);
Task<DateTime> RestoreAsync(IEnumerable<Guid> ids, Guid userId);

View File

@ -1,4 +1,6 @@
using System.Text.Json;
using Bit.Core.AdminConsole.Enums;
using Bit.Core.AdminConsole.Services;
using Bit.Core.Context;
using Bit.Core.Entities;
using Bit.Core.Enums;
@ -25,6 +27,7 @@ public class CipherService : ICipherService
private readonly ICollectionRepository _collectionRepository;
private readonly IUserRepository _userRepository;
private readonly IOrganizationRepository _organizationRepository;
private readonly IOrganizationUserRepository _organizationUserRepository;
private readonly ICollectionCipherRepository _collectionCipherRepository;
private readonly IPushNotificationService _pushService;
private readonly IAttachmentStorageService _attachmentStorageService;
@ -32,7 +35,7 @@ public class CipherService : ICipherService
private readonly IUserService _userService;
private readonly IPolicyService _policyService;
private readonly GlobalSettings _globalSettings;
private const long _fileSizeLeeway = 1024L * 1024L; // 1MB
private const long _fileSizeLeeway = 1024L * 1024L; // 1MB
private readonly IReferenceEventService _referenceEventService;
private readonly ICurrentContext _currentContext;
@ -42,6 +45,7 @@ public class CipherService : ICipherService
ICollectionRepository collectionRepository,
IUserRepository userRepository,
IOrganizationRepository organizationRepository,
IOrganizationUserRepository organizationUserRepository,
ICollectionCipherRepository collectionCipherRepository,
IPushNotificationService pushService,
IAttachmentStorageService attachmentStorageService,
@ -57,6 +61,7 @@ public class CipherService : ICipherService
_collectionRepository = collectionRepository;
_userRepository = userRepository;
_organizationRepository = organizationRepository;
_organizationUserRepository = organizationUserRepository;
_collectionCipherRepository = collectionCipherRepository;
_pushService = pushService;
_attachmentStorageService = attachmentStorageService;
@ -650,7 +655,7 @@ public class CipherService : ICipherService
cipher.RevisionDate = DateTime.UtcNow;
// The sprocs will validate that all collections belong to this org/user and that they have
// The sprocs will validate that all collections belong to this org/user and that they have
// proper write permissions.
if (orgAdmin)
{
@ -745,6 +750,7 @@ public class CipherService : ICipherService
var org = collections.Count > 0 ?
await _organizationRepository.GetByIdAsync(collections[0].OrganizationId) :
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)
{
@ -762,18 +768,25 @@ public class CipherService : ICipherService
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
//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)
{
if (!userCollectionsIds.Contains(collection.Id))
if (!organizationCollectionsIds.Contains(collection.Id))
{
collection.SetNewId();
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
await _cipherRepository.CreateAsync(ciphers, newCollections, collectionCiphers);
await _cipherRepository.CreateAsync(ciphers, newCollections, collectionCiphers, newCollectionUsers);
// push
await _pushService.PushSyncVaultAsync(importingUserId);

View File

@ -131,6 +131,16 @@
"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": {
"type": "Direct",
"requested": "[3.0.1, )",
@ -150,29 +160,6 @@
"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": {
"type": "Direct",
"requested": "[8.0.0, )",
@ -465,6 +452,15 @@
"resolved": "2.2.1",
"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": {
"type": "Transitive",
"resolved": "3.0.1",
@ -484,28 +480,8 @@
},
"IdentityModel": {
"type": "Transitive",
"resolved": "4.4.0",
"contentHash": "b18wrIx5wnZlMxAX7oVsE+nDtAJ4hajYlH0xPlaRvo4r/fz08K6pPeZvbiqS9nfNbzfIgLFmNX+FL9qR9ZR5PA==",
"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"
}
"resolved": "6.0.0",
"contentHash": "eVHCR7a6m/dm5RFcBzE3qs/Jg5j9R5Rjpu8aTOv9e4AFvaQtBXb5ah7kmwU+YwA0ufRwz4wf1hnIvsD2hSnI4g=="
},
"LaunchDarkly.Cache": {
"type": "Transitive",
@ -554,10 +530,10 @@
},
"Microsoft.AspNetCore.Authentication.OpenIdConnect": {
"type": "Transitive",
"resolved": "3.1.0",
"contentHash": "O1cAQYUTU8EfRqwc5/rfTns4E4hKlFlg59fuKRrST+PzsxI6H07KqRN/JjdYhAuVYxF8jPnIGbj+zuc5paOWUw==",
"resolved": "6.0.0",
"contentHash": "cJxdro36spFzk/K2OFCddM6vZ+yoj6ug8mTFRH3Gdv1Pul/buSuCtfb/FSCp31UmS5S4C1315dU7wX3ErLFuDg==",
"dependencies": {
"Microsoft.IdentityModel.Protocols.OpenIdConnect": "5.5.0"
"Microsoft.IdentityModel.Protocols.OpenIdConnect": "6.10.0"
}
},
"Microsoft.AspNetCore.Cryptography.Internal": {
@ -590,8 +566,8 @@
},
"Microsoft.AspNetCore.DataProtection.Abstractions": {
"type": "Transitive",
"resolved": "3.1.32",
"contentHash": "MPL4iVyiaRxnOUY5VATHjvhDWaAEFb77KFiUxVRklv3Z3v+STofUr1UG/aCt1O9cgN7FVTDaC5A7U+zsLub8Xg=="
"resolved": "6.0.0",
"contentHash": "Z/UU4NEBm5UgNufJmw+j5baW26ytCOIZ0G7sZocPaOzsUeBon1bkM3lSMNZQG2GmDjAIVP2XMSODf2jzSGbibw=="
},
"Microsoft.Azure.Amqp": {
"type": "Transitive",

View File

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

View File

@ -184,6 +184,24 @@
"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": {
"type": "Transitive",
"resolved": "3.0.1",
@ -220,49 +238,8 @@
},
"IdentityModel": {
"type": "Transitive",
"resolved": "4.4.0",
"contentHash": "b18wrIx5wnZlMxAX7oVsE+nDtAJ4hajYlH0xPlaRvo4r/fz08K6pPeZvbiqS9nfNbzfIgLFmNX+FL9qR9ZR5PA==",
"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"
}
"resolved": "6.0.0",
"contentHash": "eVHCR7a6m/dm5RFcBzE3qs/Jg5j9R5Rjpu8aTOv9e4AFvaQtBXb5ah7kmwU+YwA0ufRwz4wf1hnIvsD2hSnI4g=="
},
"LaunchDarkly.Cache": {
"type": "Transitive",
@ -354,10 +331,10 @@
},
"Microsoft.AspNetCore.Authentication.OpenIdConnect": {
"type": "Transitive",
"resolved": "3.1.0",
"contentHash": "O1cAQYUTU8EfRqwc5/rfTns4E4hKlFlg59fuKRrST+PzsxI6H07KqRN/JjdYhAuVYxF8jPnIGbj+zuc5paOWUw==",
"resolved": "6.0.0",
"contentHash": "cJxdro36spFzk/K2OFCddM6vZ+yoj6ug8mTFRH3Gdv1Pul/buSuCtfb/FSCp31UmS5S4C1315dU7wX3ErLFuDg==",
"dependencies": {
"Microsoft.IdentityModel.Protocols.OpenIdConnect": "5.5.0"
"Microsoft.IdentityModel.Protocols.OpenIdConnect": "6.10.0"
}
},
"Microsoft.AspNetCore.Cryptography.Internal": {
@ -390,8 +367,8 @@
},
"Microsoft.AspNetCore.DataProtection.Abstractions": {
"type": "Transitive",
"resolved": "3.1.32",
"contentHash": "MPL4iVyiaRxnOUY5VATHjvhDWaAEFb77KFiUxVRklv3Z3v+STofUr1UG/aCt1O9cgN7FVTDaC5A7U+zsLub8Xg=="
"resolved": "6.0.0",
"contentHash": "Z/UU4NEBm5UgNufJmw+j5baW26ytCOIZ0G7sZocPaOzsUeBon1bkM3lSMNZQG2GmDjAIVP2XMSODf2jzSGbibw=="
},
"Microsoft.Azure.Amqp": {
"type": "Transitive",
@ -2617,10 +2594,9 @@
"BitPay.Light": "[1.0.1907, )",
"Braintree": "[5.19.0, )",
"DnsClient": "[1.7.0, )",
"Duende.IdentityServer": "[6.0.4, )",
"Fido2.AspNet": "[3.0.1, )",
"Handlebars.Net": "[2.1.2, )",
"IdentityServer4": "[4.1.2, )",
"IdentityServer4.AccessTokenValidation": "[3.0.1, )",
"LaunchDarkly.ServerSdk": "[8.0.0, )",
"MailKit": "[4.2.0, )",
"Microsoft.AspNetCore.Authentication.JwtBearer": "[6.0.4, )",
@ -2648,7 +2624,7 @@
"infrastructure.dapper": {
"type": "Project",
"dependencies": {
"Core": "[2023.10.2, )",
"Core": "[2023.10.3, )",
"Dapper": "[2.0.123, )"
}
},
@ -2656,7 +2632,7 @@
"type": "Project",
"dependencies": {
"AutoMapper.Extensions.Microsoft.DependencyInjection": "[12.0.1, )",
"Core": "[2023.10.2, )",
"Core": "[2023.10.3, )",
"Microsoft.EntityFrameworkCore.Relational": "[7.0.5, )",
"Microsoft.EntityFrameworkCore.SqlServer": "[7.0.5, )",
"Microsoft.EntityFrameworkCore.Sqlite": "[7.0.5, )",
@ -2668,9 +2644,9 @@
"sharedweb": {
"type": "Project",
"dependencies": {
"Core": "[2023.10.2, )",
"Infrastructure.Dapper": "[2023.10.2, )",
"Infrastructure.EntityFramework": "[2023.10.2, )"
"Core": "[2023.10.3, )",
"Infrastructure.Dapper": "[2023.10.3, )",
"Infrastructure.EntityFramework": "[2023.10.3, )"
}
}
}

View File

@ -184,6 +184,24 @@
"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": {
"type": "Transitive",
"resolved": "3.0.1",
@ -220,49 +238,8 @@
},
"IdentityModel": {
"type": "Transitive",
"resolved": "4.4.0",
"contentHash": "b18wrIx5wnZlMxAX7oVsE+nDtAJ4hajYlH0xPlaRvo4r/fz08K6pPeZvbiqS9nfNbzfIgLFmNX+FL9qR9ZR5PA==",
"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"
}
"resolved": "6.0.0",
"contentHash": "eVHCR7a6m/dm5RFcBzE3qs/Jg5j9R5Rjpu8aTOv9e4AFvaQtBXb5ah7kmwU+YwA0ufRwz4wf1hnIvsD2hSnI4g=="
},
"LaunchDarkly.Cache": {
"type": "Transitive",
@ -354,10 +331,10 @@
},
"Microsoft.AspNetCore.Authentication.OpenIdConnect": {
"type": "Transitive",
"resolved": "3.1.0",
"contentHash": "O1cAQYUTU8EfRqwc5/rfTns4E4hKlFlg59fuKRrST+PzsxI6H07KqRN/JjdYhAuVYxF8jPnIGbj+zuc5paOWUw==",
"resolved": "6.0.0",
"contentHash": "cJxdro36spFzk/K2OFCddM6vZ+yoj6ug8mTFRH3Gdv1Pul/buSuCtfb/FSCp31UmS5S4C1315dU7wX3ErLFuDg==",
"dependencies": {
"Microsoft.IdentityModel.Protocols.OpenIdConnect": "5.5.0"
"Microsoft.IdentityModel.Protocols.OpenIdConnect": "6.10.0"
}
},
"Microsoft.AspNetCore.Cryptography.Internal": {
@ -390,8 +367,8 @@
},
"Microsoft.AspNetCore.DataProtection.Abstractions": {
"type": "Transitive",
"resolved": "3.1.32",
"contentHash": "MPL4iVyiaRxnOUY5VATHjvhDWaAEFb77KFiUxVRklv3Z3v+STofUr1UG/aCt1O9cgN7FVTDaC5A7U+zsLub8Xg=="
"resolved": "6.0.0",
"contentHash": "Z/UU4NEBm5UgNufJmw+j5baW26ytCOIZ0G7sZocPaOzsUeBon1bkM3lSMNZQG2GmDjAIVP2XMSODf2jzSGbibw=="
},
"Microsoft.Azure.Amqp": {
"type": "Transitive",
@ -2617,10 +2594,9 @@
"BitPay.Light": "[1.0.1907, )",
"Braintree": "[5.19.0, )",
"DnsClient": "[1.7.0, )",
"Duende.IdentityServer": "[6.0.4, )",
"Fido2.AspNet": "[3.0.1, )",
"Handlebars.Net": "[2.1.2, )",
"IdentityServer4": "[4.1.2, )",
"IdentityServer4.AccessTokenValidation": "[3.0.1, )",
"LaunchDarkly.ServerSdk": "[8.0.0, )",
"MailKit": "[4.2.0, )",
"Microsoft.AspNetCore.Authentication.JwtBearer": "[6.0.4, )",
@ -2648,7 +2624,7 @@
"infrastructure.dapper": {
"type": "Project",
"dependencies": {
"Core": "[2023.10.2, )",
"Core": "[2023.10.3, )",
"Dapper": "[2.0.123, )"
}
},
@ -2656,7 +2632,7 @@
"type": "Project",
"dependencies": {
"AutoMapper.Extensions.Microsoft.DependencyInjection": "[12.0.1, )",
"Core": "[2023.10.2, )",
"Core": "[2023.10.3, )",
"Microsoft.EntityFrameworkCore.Relational": "[7.0.5, )",
"Microsoft.EntityFrameworkCore.SqlServer": "[7.0.5, )",
"Microsoft.EntityFrameworkCore.Sqlite": "[7.0.5, )",
@ -2668,9 +2644,9 @@
"sharedweb": {
"type": "Project",
"dependencies": {
"Core": "[2023.10.2, )",
"Infrastructure.Dapper": "[2023.10.2, )",
"Infrastructure.EntityFramework": "[2023.10.2, )"
"Core": "[2023.10.3, )",
"Infrastructure.Dapper": "[2023.10.3, )",
"Infrastructure.EntityFramework": "[2023.10.3, )"
}
}
}

View File

@ -193,6 +193,24 @@
"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": {
"type": "Transitive",
"resolved": "3.0.1",
@ -229,49 +247,8 @@
},
"IdentityModel": {
"type": "Transitive",
"resolved": "4.4.0",
"contentHash": "b18wrIx5wnZlMxAX7oVsE+nDtAJ4hajYlH0xPlaRvo4r/fz08K6pPeZvbiqS9nfNbzfIgLFmNX+FL9qR9ZR5PA==",
"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"
}
"resolved": "6.0.0",
"contentHash": "eVHCR7a6m/dm5RFcBzE3qs/Jg5j9R5Rjpu8aTOv9e4AFvaQtBXb5ah7kmwU+YwA0ufRwz4wf1hnIvsD2hSnI4g=="
},
"LaunchDarkly.Cache": {
"type": "Transitive",
@ -363,10 +340,10 @@
},
"Microsoft.AspNetCore.Authentication.OpenIdConnect": {
"type": "Transitive",
"resolved": "3.1.0",
"contentHash": "O1cAQYUTU8EfRqwc5/rfTns4E4hKlFlg59fuKRrST+PzsxI6H07KqRN/JjdYhAuVYxF8jPnIGbj+zuc5paOWUw==",
"resolved": "6.0.0",
"contentHash": "cJxdro36spFzk/K2OFCddM6vZ+yoj6ug8mTFRH3Gdv1Pul/buSuCtfb/FSCp31UmS5S4C1315dU7wX3ErLFuDg==",
"dependencies": {
"Microsoft.IdentityModel.Protocols.OpenIdConnect": "5.5.0"
"Microsoft.IdentityModel.Protocols.OpenIdConnect": "6.10.0"
}
},
"Microsoft.AspNetCore.Cryptography.Internal": {
@ -399,8 +376,8 @@
},
"Microsoft.AspNetCore.DataProtection.Abstractions": {
"type": "Transitive",
"resolved": "3.1.32",
"contentHash": "MPL4iVyiaRxnOUY5VATHjvhDWaAEFb77KFiUxVRklv3Z3v+STofUr1UG/aCt1O9cgN7FVTDaC5A7U+zsLub8Xg=="
"resolved": "6.0.0",
"contentHash": "Z/UU4NEBm5UgNufJmw+j5baW26ytCOIZ0G7sZocPaOzsUeBon1bkM3lSMNZQG2GmDjAIVP2XMSODf2jzSGbibw=="
},
"Microsoft.Azure.Amqp": {
"type": "Transitive",
@ -2626,10 +2603,9 @@
"BitPay.Light": "[1.0.1907, )",
"Braintree": "[5.19.0, )",
"DnsClient": "[1.7.0, )",
"Duende.IdentityServer": "[6.0.4, )",
"Fido2.AspNet": "[3.0.1, )",
"Handlebars.Net": "[2.1.2, )",
"IdentityServer4": "[4.1.2, )",
"IdentityServer4.AccessTokenValidation": "[3.0.1, )",
"LaunchDarkly.ServerSdk": "[8.0.0, )",
"MailKit": "[4.2.0, )",
"Microsoft.AspNetCore.Authentication.JwtBearer": "[6.0.4, )",
@ -2657,7 +2633,7 @@
"infrastructure.dapper": {
"type": "Project",
"dependencies": {
"Core": "[2023.10.2, )",
"Core": "[2023.10.3, )",
"Dapper": "[2.0.123, )"
}
},
@ -2665,7 +2641,7 @@
"type": "Project",
"dependencies": {
"AutoMapper.Extensions.Microsoft.DependencyInjection": "[12.0.1, )",
"Core": "[2023.10.2, )",
"Core": "[2023.10.3, )",
"Microsoft.EntityFrameworkCore.Relational": "[7.0.5, )",
"Microsoft.EntityFrameworkCore.SqlServer": "[7.0.5, )",
"Microsoft.EntityFrameworkCore.Sqlite": "[7.0.5, )",
@ -2677,9 +2653,9 @@
"sharedweb": {
"type": "Project",
"dependencies": {
"Core": "[2023.10.2, )",
"Infrastructure.Dapper": "[2023.10.2, )",
"Infrastructure.EntityFramework": "[2023.10.2, )"
"Core": "[2023.10.3, )",
"Infrastructure.Dapper": "[2023.10.3, )",
"Infrastructure.EntityFramework": "[2023.10.3, )"
}
}
}

View File

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

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