mirror of
https://github.com/bitwarden/mobile
synced 2025-12-14 07:13:33 +00:00
[PM-5731] feat: add sameOriginWithAncestor and user id length checks
This commit is contained in:
@@ -5,7 +5,25 @@ namespace Bit.Core.Services
|
|||||||
{
|
{
|
||||||
public class Fido2ClientService : IFido2ClientService
|
public class Fido2ClientService : IFido2ClientService
|
||||||
{
|
{
|
||||||
public Task<Fido2ClientCreateCredentialResult> CreateCredentialAsync(Fido2ClientCreateCredentialParams createCredentialParams) => throw new NotImplementedException();
|
public Task<Fido2ClientCreateCredentialResult> CreateCredentialAsync(Fido2ClientCreateCredentialParams createCredentialParams)
|
||||||
|
{
|
||||||
|
if (!createCredentialParams.SameOriginWithAncestors)
|
||||||
|
{
|
||||||
|
throw new Fido2ClientException(
|
||||||
|
Fido2ClientException.ErrorCode.NotAllowedError,
|
||||||
|
"Credential creation is now allowed from embedded contexts with different origins.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (createCredentialParams.User.Id.Length < 1 || createCredentialParams.User.Id.Length > 64)
|
||||||
|
{
|
||||||
|
// TODO: Should we use ArgumentException here instead?
|
||||||
|
throw new Fido2ClientException(
|
||||||
|
Fido2ClientException.ErrorCode.TypeError,
|
||||||
|
"The length of user.id is not between 1 and 64 bytes (inclusive).");
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
public Task<Fido2ClientAssertCredentialResult> AssertCredentialAsync(Fido2ClientAssertCredentialParams assertCredentialParams) => throw new NotImplementedException();
|
public Task<Fido2ClientAssertCredentialResult> AssertCredentialAsync(Fido2ClientAssertCredentialParams assertCredentialParams) => throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ namespace Bit.Core.Utilities.Fido2
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public required string Origin { get; set; }
|
public required string Origin { get; set; }
|
||||||
|
|
||||||
|
// TODO: Check if we actually need this
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A value which is true if and only if the caller’s environment settings object is same-origin with its ancestors.
|
/// A value which is true if and only if the caller’s environment settings object is same-origin with its ancestors.
|
||||||
/// It is false if caller is cross-origin.
|
/// It is false if caller is cross-origin.
|
||||||
|
|||||||
22
src/Core/Utilities/Fido2/Fido2ClientException.cs
Normal file
22
src/Core/Utilities/Fido2/Fido2ClientException.cs
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
namespace Bit.Core.Utilities.Fido2
|
||||||
|
{
|
||||||
|
public class Fido2ClientException : Exception
|
||||||
|
{
|
||||||
|
public enum ErrorCode
|
||||||
|
{
|
||||||
|
NotAllowedError,
|
||||||
|
TypeError,
|
||||||
|
SecurityError,
|
||||||
|
UnknownError
|
||||||
|
}
|
||||||
|
|
||||||
|
public readonly ErrorCode Code;
|
||||||
|
public readonly string Reason;
|
||||||
|
|
||||||
|
public Fido2ClientException(ErrorCode code, string reason) : base($"{code} ({reason})")
|
||||||
|
{
|
||||||
|
Code = code;
|
||||||
|
Reason = reason;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
86
test/Core.Test/Services/Fido2ClientCreateCredentialTests.cs
Normal file
86
test/Core.Test/Services/Fido2ClientCreateCredentialTests.cs
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Bit.Core.Services;
|
||||||
|
using Bit.Core.Utilities.Fido2;
|
||||||
|
using Bit.Test.Common.AutoFixture;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace Bit.Core.Test.Services
|
||||||
|
{
|
||||||
|
public class Fido2ClientCreateCredentialTests : IDisposable
|
||||||
|
{
|
||||||
|
private readonly SutProvider<Fido2ClientService> _sutProvider = new SutProvider<Fido2ClientService>().Create();
|
||||||
|
|
||||||
|
private Fido2ClientCreateCredentialParams _params;
|
||||||
|
|
||||||
|
public Fido2ClientCreateCredentialTests()
|
||||||
|
{
|
||||||
|
_params = new Fido2ClientCreateCredentialParams {
|
||||||
|
Origin = "https://bitwarden.com",
|
||||||
|
SameOriginWithAncestors = true,
|
||||||
|
Attestation = "none",
|
||||||
|
Challenge = RandomBytes(32),
|
||||||
|
PubKeyCredParams = [
|
||||||
|
new PublicKeyCredentialParameters {
|
||||||
|
Type = "public-key",
|
||||||
|
Alg = -7
|
||||||
|
}
|
||||||
|
],
|
||||||
|
Rp = new PublicKeyCredentialRpEntity {
|
||||||
|
Id = "bitwarden.com",
|
||||||
|
Name = "Bitwarden"
|
||||||
|
},
|
||||||
|
User = new PublicKeyCredentialUserEntity {
|
||||||
|
Id = RandomBytes(32),
|
||||||
|
Name = "user@bitwarden.com",
|
||||||
|
DisplayName = "User"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
// Spec: If sameOriginWithAncestors is false, return a "NotAllowedError" DOMException.
|
||||||
|
public async Task CreateCredentialAsync_ThrowsNotAllowedError_SameOriginWithAncestorsIsFalse()
|
||||||
|
{
|
||||||
|
_params.SameOriginWithAncestors = false;
|
||||||
|
|
||||||
|
var exception = await Assert.ThrowsAsync<Fido2ClientException>(() => _sutProvider.Sut.CreateCredentialAsync(_params));
|
||||||
|
|
||||||
|
Assert.Equal(Fido2ClientException.ErrorCode.NotAllowedError, exception.Code);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
// Spec: If the length of options.user.id is not between 1 and 64 bytes (inclusive) then return a TypeError.
|
||||||
|
public async Task CreateCredentialAsync_ThrowsTypeError_UserIdIsTooSmall()
|
||||||
|
{
|
||||||
|
_params.User.Id = RandomBytes(0);
|
||||||
|
|
||||||
|
var exception = await Assert.ThrowsAsync<Fido2ClientException>(() => _sutProvider.Sut.CreateCredentialAsync(_params));
|
||||||
|
|
||||||
|
Assert.Equal(Fido2ClientException.ErrorCode.TypeError, exception.Code);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
// Spec: If the length of options.user.id is not between 1 and 64 bytes (inclusive) then return a TypeError.
|
||||||
|
public async Task CreateCredentialAsync_ThrowsTypeError_UserIdIsTooLarge()
|
||||||
|
{
|
||||||
|
_params.User.Id = RandomBytes(65);
|
||||||
|
|
||||||
|
var exception = await Assert.ThrowsAsync<Fido2ClientException>(() => _sutProvider.Sut.CreateCredentialAsync(_params));
|
||||||
|
|
||||||
|
Assert.Equal(Fido2ClientException.ErrorCode.TypeError, exception.Code);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private byte[] RandomBytes(int length)
|
||||||
|
{
|
||||||
|
var bytes = new byte[length];
|
||||||
|
new Random().NextBytes(bytes);
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user