1
0
mirror of https://github.com/bitwarden/server.git synced 2025-06-30 07:36:14 -05:00

[PM-2697] Return UserDecryptionOptions Always (#3032)

* Add Comments to UserDecryptionOptions

* Move Feature Flag Check

* Remove SSO Config Check

* Move UserDecryptionOptions Creation

- Put logic in BaseRequestValidator

* Remove 'async'
This commit is contained in:
Justin Baur
2023-06-26 20:17:39 -04:00
committed by GitHub
parent e96fc56dc2
commit e0b231a220
6 changed files with 161 additions and 85 deletions

View File

@ -245,6 +245,59 @@ public class IdentityServerSsoTests
AssertHelper.AssertJsonProperty(trustedDeviceOption, "HasAdminApproval", JsonValueKind.False);
}
[Fact]
public async Task SsoLogin_TrustedDeviceEncryption_FlagTurnedOff_DoesNotReturnOption()
{
// Arrange
var challenge = new string('c', 50);
// This creates SsoConfig that HAS enabled trusted device encryption which should have only been
// done with the feature flag turned on but we are testing that even if they have done that, this will turn off
// if returning as an option if the flag has later been turned off. We should be very careful turning the flag
// back off.
var factory = await CreateFactoryAsync(new SsoConfigurationData
{
MemberDecryptionType = MemberDecryptionType.TrustedDeviceEncryption,
}, challenge, trustedDeviceEnabled: false);
await UpdateUserAsync(factory, user => user.MasterPassword = null);
// Act
var context = await factory.Server.PostAsync("/connect/token", new FormUrlEncodedContent(new Dictionary<string, string>
{
{ "scope", "api offline_access" },
{ "client_id", "web" },
{ "deviceType", "10" },
{ "deviceIdentifier", "test_id" },
{ "deviceName", "firefox" },
{ "twoFactorToken", "TEST"},
{ "twoFactorProvider", "5" }, // RememberMe Provider
{ "twoFactorRemember", "0" },
{ "grant_type", "authorization_code" },
{ "code", "test_code" },
{ "code_verifier", challenge },
{ "redirect_uri", "https://localhost:8080/sso-connector.html" }
}));
// Assert
// If the organization has selected TrustedDeviceEncryption but the user still has their master password
// they can decrypt with either option
Assert.Equal(StatusCodes.Status200OK, context.Response.StatusCode);
using var responseBody = await AssertHelper.AssertResponseTypeIs<JsonDocument>(context);
var root = responseBody.RootElement;
AssertHelper.AssertJsonProperty(root, "access_token", JsonValueKind.String);
var userDecryptionOptions = AssertHelper.AssertJsonProperty(root, "UserDecryptionOptions", JsonValueKind.Object);
// Expected to look like:
// "UserDecryptionOptions": {
// "Object": "userDecryptionOptions"
// "HasMasterPassword": false
// }
// Should only have 2 properties
Assert.Equal(2, userDecryptionOptions.EnumerateObject().Count());
}
[Fact]
public async Task SsoLogin_KeyConnector_ReturnsOptions()
{
@ -301,7 +354,7 @@ public class IdentityServerSsoTests
Assert.Equal("https://key_connector.com", keyConnectorUrl);
}
private static async Task<IdentityApplicationFactory> CreateFactoryAsync(SsoConfigurationData ssoConfigurationData, string challenge)
private static async Task<IdentityApplicationFactory> CreateFactoryAsync(SsoConfigurationData ssoConfigurationData, string challenge, bool trustedDeviceEnabled = true)
{
var factory = new IdentityApplicationFactory();
@ -327,7 +380,7 @@ public class IdentityServerSsoTests
factory.SubstitueService<IFeatureService>(service =>
{
service.IsEnabled(FeatureFlagKeys.TrustedDeviceEncryption, Arg.Any<ICurrentContext>())
.Returns(true);
.Returns(trustedDeviceEnabled);
});
// This starts the server and finalizes services

View File

@ -65,6 +65,7 @@ public class IdentityServerTests : IClassFixture<IdentityApplicationFactory>
Assert.Equal(0, kdf);
var kdfIterations = AssertHelper.AssertJsonProperty(root, "KdfIterations", JsonValueKind.Number).GetInt32();
Assert.Equal(5000, kdfIterations);
AssertUserDecryptionOptions(root);
}
[Theory, BitAutoData]
@ -635,6 +636,16 @@ public class IdentityServerTests : IClassFixture<IdentityApplicationFactory>
Assert.StartsWith("sso authentication", errorDescription.ToLowerInvariant());
}
private static void AssertUserDecryptionOptions(JsonElement tokenResponse)
{
var userDecryptionOptions = AssertHelper.AssertJsonProperty(tokenResponse, "UserDecryptionOptions", JsonValueKind.Object)
.EnumerateObject();
Assert.Collection(userDecryptionOptions,
(prop) => { Assert.Equal("HasMasterPassword", prop.Name); Assert.Equal(JsonValueKind.True, prop.Value.ValueKind); },
(prop) => { Assert.Equal("Object", prop.Name); Assert.Equal("userDecryptionOptions", prop.Value.GetString()); });
}
private void ReinitializeDbForTests()
{
var databaseContext = _factory.GetDatabaseContext();