Skip to content

Commit 20501e0

Browse files
vpetruseviciVladimir PetruseviciAnders Åberg
authored
Add support for JsonStringEnumMemberName and X509CertificateLoader for .net10 (#651)
* Add .NET 9+ compatibility updates, including conditional attributes, improved type handling, and JsonStringEnumMemberName attribute. * Update nuget.config * Pin LangVersion to 14 and fix SupportedTargetFrameworks formatting * code cleanup * cleanup * fix tests * revert tmp changes * remove FidoEnumConverter and EnumMember for .net9+ * update LangVersion to 13 in Directory.Build.props * move certificate loading to helper * remove unnecessary null check * fix test * fix test * fix exception handling in AndroidSafetyNet tests and simplify X509 certificate loading * Update AndroidSafetyNet.cs * simplify exception assertion in AndroidSafetyNet test --------- Co-authored-by: Vladimir Petrusevici <V.Petrusevici@maib.md> Co-authored-by: Anders Åberg <anders@m5.localdomain>
1 parent 5e556bd commit 20501e0

29 files changed

Lines changed: 343 additions & 38 deletions

Directory.Build.props

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

1717
<!-- Global Variables -->
1818
<PropertyGroup>
19-
<SupportedTargetFrameworks>net8.0</SupportedTargetFrameworks>
19+
<SupportedTargetFrameworks>net8.0;net10.0</SupportedTargetFrameworks>
2020
<ImplicitUsings>enable</ImplicitUsings>
2121
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
2222
<GenerateDocumentationFile>true</GenerateDocumentationFile>
@@ -29,7 +29,7 @@
2929

3030
<!-- Language + Compiler Settings-->
3131
<PropertyGroup>
32-
<LangVersion>12</LangVersion>
32+
<LangVersion>13</LangVersion>
3333
</PropertyGroup>
3434

3535
<!--MISC-->

Src/Fido2.Models/Converters/EnumNameMapper.cs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using System.Diagnostics.CodeAnalysis;
33
using System.Reflection;
44
using System.Runtime.Serialization;
5+
using System.Text.Json.Serialization;
56

67
namespace Fido2NetLib;
78

@@ -45,11 +46,15 @@ private static FrozenDictionary<TEnum, string> GetIdToNameMap()
4546

4647
foreach (var field in typeof(TEnum).GetFields(BindingFlags.Public | BindingFlags.Static))
4748
{
48-
var description = field.GetCustomAttribute<EnumMemberAttribute>(false);
49+
#if NET9_0_OR_GREATER
50+
var description = field.GetCustomAttribute<JsonStringEnumMemberNameAttribute>(false)?.Name;
51+
#else
52+
var description = field.GetCustomAttribute<EnumMemberAttribute>(false)?.Value;
53+
#endif
4954

5055
var value = (TEnum)field.GetValue(null)!;
5156

52-
items.Add(new(value, description is not null ? description.Value! : value.ToString()));
57+
items.Add(new(value, description ?? value.ToString()));
5358
}
5459

5560
return items.ToFrozenDictionary();

Src/Fido2.Models/Fido2Configuration.cs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#nullable disable
22

33
using System.Runtime.Serialization;
4+
using System.Text.Json.Serialization;
45

56
namespace Fido2NetLib;
67

@@ -114,19 +115,31 @@ public enum CredentialBackupPolicy
114115
/// <summary>
115116
/// This value indicates that the Relying Party requires backup eligible or backed up credentials.
116117
/// </summary>
118+
#if NET9_0_OR_GREATER
119+
[JsonStringEnumMemberName("required")]
120+
#else
117121
[EnumMember(Value = "required")]
122+
#endif
118123
Required,
119124

120125
/// <summary>
121126
/// This value indicates that the Relying Party allows backup eligible or backed up credentials.
122127
/// </summary>
128+
#if NET9_0_OR_GREATER
129+
[JsonStringEnumMemberName("allowed")]
130+
#else
123131
[EnumMember(Value = "allowed")]
132+
#endif
124133
Allowed,
125134

126135
/// <summary>
127136
/// This value indicates that the Relying Party does not allow backup eligible or backed up credentials.
128137
/// </summary>
138+
#if NET9_0_OR_GREATER
139+
[JsonStringEnumMemberName("disallowed")]
140+
#else
129141
[EnumMember(Value = "disallowed")]
142+
#endif
130143
Disallowed
131144
}
132145
}

Src/Fido2.Models/Metadata/UserVerificationMethods.cs

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,72 +10,128 @@ namespace Fido2NetLib;
1010
*
1111
* https://fidoalliance.org/specs/fido-uaf-v1.0-ps-20141208/fido-uaf-reg-v1.0-ps-20141208.html#user-verification-methods
1212
*/
13+
#if NET9_0_OR_GREATER
14+
[JsonConverter(typeof(JsonStringEnumConverter<UserVerificationMethods>))]
15+
#else
1316
[JsonConverter(typeof(FidoEnumConverter<UserVerificationMethods>))]
17+
#endif
1418
public enum UserVerificationMethods
1519
{
1620
/// <summary>
1721
/// This flag must be set if the authenticator is able to confirm user presence in any fashion. If this flag and no other is set for user verification, the guarantee is only that the authenticator cannot be operated without some human intervention, not necessarily that the presence verification provides any level of authentication of the human's identity. (e.g. a device that requires a touch to activate)
1822
/// </summary>
23+
#if NET9_0_OR_GREATER
24+
[JsonStringEnumMemberName("presence_internal")]
25+
#else
1926
[EnumMember(Value = "presence_internal")]
27+
#endif
2028
PRESENCE_INTERNAL = 1,
2129
/// <summary>
2230
/// This flag must be set if the authenticator uses any type of measurement of a fingerprint for user verification.
2331
/// </summary>
32+
#if NET9_0_OR_GREATER
33+
[JsonStringEnumMemberName("fingerprint_internal")]
34+
#else
2435
[EnumMember(Value = "fingerprint_internal")]
36+
#endif
2537
FINGERPRINT_INTERNAL = 2,
2638
/// <summary>
2739
/// This flag must be set if the authenticator uses a local-only passcode (i.e. a passcode not known by the server) for user verification.
2840
/// </summary>
41+
#if NET9_0_OR_GREATER
42+
[JsonStringEnumMemberName("passcode_internal")]
43+
#else
2944
[EnumMember(Value = "passcode_internal")]
45+
#endif
3046
PASSCODE_INTERNAL = 4,
3147
/// <summary>
3248
/// This flag must be set if the authenticator uses a voiceprint (also known as speaker recognition) for user verification.
3349
/// </summary>
50+
#if NET9_0_OR_GREATER
51+
[JsonStringEnumMemberName("voiceprint_internal")]
52+
#else
3453
[EnumMember(Value = "voiceprint_internal")]
54+
#endif
3555
VOICEPRINT_INTERNAL = 8,
3656
/// <summary>
3757
/// This flag must be set if the authenticator uses any manner of face recognition to verify the user.
3858
/// </summary>
59+
#if NET9_0_OR_GREATER
60+
[JsonStringEnumMemberName("faceprint_internal")]
61+
#else
3962
[EnumMember(Value = "faceprint_internal")]
63+
#endif
4064
FACEPRINT_INTERNAL = 0x10,
4165
/// <summary>
4266
/// This flag must be set if the authenticator uses any form of location sensor or measurement for user verification.
4367
/// </summary>
68+
#if NET9_0_OR_GREATER
69+
[JsonStringEnumMemberName("location_internal")]
70+
#else
4471
[EnumMember(Value = "location_internal")]
72+
#endif
4573
LOCATION_INTERNAL = 0x20,
4674
/// <summary>
4775
/// This flag must be set if the authenticator uses any form of eye biometrics for user verification.
4876
/// </summary>
77+
#if NET9_0_OR_GREATER
78+
[JsonStringEnumMemberName("eyeprint_internal")]
79+
#else
4980
[EnumMember(Value = "eyeprint_internal")]
81+
#endif
5082
EYEPRINT_INTERNAL = 0x40,
5183
/// <summary>
5284
/// This flag must be set if the authenticator uses a drawn pattern for user verification.
5385
/// </summary>
86+
#if NET9_0_OR_GREATER
87+
[JsonStringEnumMemberName("pattern_internal")]
88+
#else
5489
[EnumMember(Value = "pattern_internal")]
90+
#endif
5591
PATTERN_INTERNAL = 0x80,
5692
/// <summary>
5793
/// This flag must be set if the authenticator uses any measurement of a full hand (including palm-print, hand geometry or vein geometry) for user verification.
5894
/// </summary>
95+
#if NET9_0_OR_GREATER
96+
[JsonStringEnumMemberName("handprint_internal")]
97+
#else
5998
[EnumMember(Value = "handprint_internal")]
99+
#endif
60100
HANDPRINT_INTERNAL = 0x100,
61101
/// <summary>
62102
/// This flag must be set if the authenticator uses a local-only passcode (i.e. a passcode not known by the server) for user verification that might be gathered outside the authenticator boundary.
63103
/// </summary>
104+
#if NET9_0_OR_GREATER
105+
[JsonStringEnumMemberName("passcode_external")]
106+
#else
64107
[EnumMember(Value = "passcode_external")]
108+
#endif
65109
PASSCODE_EXTERNAL = 0x800,
66110
/// <summary>
67111
/// This flag must be set if the authenticator uses a drawn pattern for user verification that might be gathered outside the authenticator boundary.
68112
/// </summary>
113+
#if NET9_0_OR_GREATER
114+
[JsonStringEnumMemberName("pattern_external")]
115+
#else
69116
[EnumMember(Value = "pattern_external")]
117+
#endif
70118
PATTERN_EXTERNAL = 0x1000,
71119
/// <summary>
72120
/// This flag must be set if the authenticator will respond without any user interaction (e.g. Silent Authenticator).
73121
/// </summary>
122+
#if NET9_0_OR_GREATER
123+
[JsonStringEnumMemberName("none")]
124+
#else
74125
[EnumMember(Value = "none")]
126+
#endif
75127
NONE = 0x200,
76128
/// <summary>
77129
/// If an authenticator sets multiple flags for user verification types, it may also set this flag to indicate that all verification methods will be enforced (e.g. faceprint AND voiceprint). If flags for multiple user verification methods are set and this flag is not set, verification with only one is necessary (e.g. fingerprint OR passcode).
78130
/// </summary>
131+
#if NET9_0_OR_GREATER
132+
[JsonStringEnumMemberName("all")]
133+
#else
79134
[EnumMember(Value = "all")]
135+
#endif
80136
ALL = 0x400,
81137
}

Src/Fido2.Models/Objects/AttestationConveyancePreference.cs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,31 +7,51 @@ namespace Fido2NetLib.Objects;
77
/// AttestationConveyancePreference
88
/// https://www.w3.org/TR/webauthn-2/#enum-attestation-convey
99
/// </summary>
10+
#if NET9_0_OR_GREATER
11+
[JsonConverter(typeof(JsonStringEnumConverter<AttestationConveyancePreference>))]
12+
#else
1013
[JsonConverter(typeof(FidoEnumConverter<AttestationConveyancePreference>))]
14+
#endif
1115
public enum AttestationConveyancePreference
1216
{
1317
/// <summary>
1418
/// This value indicates that the Relying Party is not interested in authenticator attestation. For example, in order to potentially avoid having to obtain user consent to relay identifying information to the Relying Party, or to save a roundtrip to an Attestation CA.
1519
/// This is the default value.
1620
/// </summary>
21+
#if NET9_0_OR_GREATER
22+
[JsonStringEnumMemberName("none")]
23+
#else
1724
[EnumMember(Value = "none")]
25+
#endif
1826
None,
1927

2028
/// <summary>
2129
/// This value indicates that the Relying Party prefers an attestation conveyance yielding verifiable attestation statements, but allows the client to decide how to obtain such attestation statements. The client MAY replace the authenticator-generated attestation statements with attestation statements generated by an Anonymization CA, in order to protect the user’s privacy, or to assist Relying Parties with attestation verification in a heterogeneous ecosystem.
2230
/// </summary>
31+
#if NET9_0_OR_GREATER
32+
[JsonStringEnumMemberName("indirect")]
33+
#else
2334
[EnumMember(Value = "indirect")]
35+
#endif
2436
Indirect,
2537

2638
/// <summary>
2739
/// This value indicates that the Relying Party wants to receive the attestation statement as generated by the authenticator.
2840
/// </summary>
41+
#if NET9_0_OR_GREATER
42+
[JsonStringEnumMemberName("direct")]
43+
#else
2944
[EnumMember(Value = "direct")]
45+
#endif
3046
Direct,
3147

3248
/// <summary>
3349
/// This value indicates that the Relying Party wants to receive an attestation statement that may include uniquely identifying information.
3450
/// </summary>
51+
#if NET9_0_OR_GREATER
52+
[JsonStringEnumMemberName("enterprise")]
53+
#else
3554
[EnumMember(Value = "enterprise")]
55+
#endif
3656
Enterprise
3757
}

Src/Fido2.Models/Objects/AttestationStatementFormatIdentifier.cs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,49 +7,81 @@ namespace Fido2NetLib.Objects;
77
/// The attestation statement format identifier in WebAuthn specifies the format of the attestation statement that is used to attest to the authenticity of a credential created by a WebAuthn authenticator.
88
/// https://www.iana.org/assignments/webauthn/webauthn.xhtml
99
/// </summary>
10+
#if NET9_0_OR_GREATER
11+
[JsonConverter(typeof(JsonStringEnumConverter<AttestationStatementFormatIdentifier>))]
12+
#else
1013
[JsonConverter(typeof(FidoEnumConverter<AttestationStatementFormatIdentifier>))]
14+
#endif
1115
public enum AttestationStatementFormatIdentifier
1216
{
1317
/// <summary>
1418
/// The "packed" attestation statement format is a WebAuthn-optimized format for attestation. It uses a very compact but still extensible encoding method. This format is implementable by authenticators with limited resources (e.g., secure elements).
1519
/// </summary>
20+
#if NET9_0_OR_GREATER
21+
[JsonStringEnumMemberName("packed")]
22+
#else
1623
[EnumMember(Value = "packed")]
24+
#endif
1725
Packed,
1826

1927
/// <summary>
2028
/// The "TPM" attestation statement format returns an attestation statement in the same format as the packed attestation statement format, although the rawData and signature fields are computed differently.
2129
/// </summary>
30+
#if NET9_0_OR_GREATER
31+
[JsonStringEnumMemberName("tpm")]
32+
#else
2233
[EnumMember(Value = "tpm")]
34+
#endif
2335
Tpm,
2436

2537
/// <summary>
2638
/// Platform authenticators on versions "N", and later, may provide this proprietary "hardware attestation" statement.
2739
/// </summary>
40+
#if NET9_0_OR_GREATER
41+
[JsonStringEnumMemberName("android-key")]
42+
#else
2843
[EnumMember(Value = "android-key")]
44+
#endif
2945
AndroidKey,
3046

3147
/// <summary>
3248
/// Android-based platform authenticators MAY produce an attestation statement based on the Android SafetyNet API.
3349
/// </summary>
50+
#if NET9_0_OR_GREATER
51+
[JsonStringEnumMemberName("android-safetynet")]
52+
#else
3453
[EnumMember(Value = "android-safetynet")]
54+
#endif
3555
AndroidSafetyNet,
3656

3757
/// <summary>
3858
/// Used with FIDO U2F authenticators.
3959
/// </summary>
60+
#if NET9_0_OR_GREATER
61+
[JsonStringEnumMemberName("fido-u2f")]
62+
#else
4063
[EnumMember(Value = "fido-u2f")]
64+
#endif
4165
FidoU2f,
4266

4367
/// <summary>
4468
/// Used with Apple devices' platform authenticators.
4569
/// </summary>
70+
#if NET9_0_OR_GREATER
71+
[JsonStringEnumMemberName("apple")]
72+
#else
4673
[EnumMember(Value = "apple")]
74+
#endif
4775
Apple,
4876

4977
/// <summary>
5078
/// Used to replace any authenticator-provided attestation statement when a WebAuthn Relying Party indicates it does not wish to receive attestation information.
5179
/// </summary>
80+
#if NET9_0_OR_GREATER
81+
[JsonStringEnumMemberName("none")]
82+
#else
5283
[EnumMember(Value = "none")]
84+
#endif
5385
None
5486
}
5587

Src/Fido2.Models/Objects/AuthenticatorAttachment.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,18 +12,30 @@ namespace Fido2NetLib.Objects;
1212
/// Note: An authenticator attachment modality selection option is available only in the [[Create]](origin, options, sameOriginWithAncestors) operation. The Relying Party may use it to, for example, ensure the user has a roaming credential for authenticating on another client device; or to specifically register a platform credential for easier reauthentication using a particular client device. The [[DiscoverFromExternalSource]](origin, options, sameOriginWithAncestors) operation has no authenticator attachment modality selection option, so the Relying Party SHOULD accept any of the user’s registered credentials. The client and user will then use whichever is available and convenient at the time.
1313
/// https://www.w3.org/TR/webauthn-2/#enum-attachment
1414
/// </remarks>
15+
#if NET9_0_OR_GREATER
16+
[JsonConverter(typeof(JsonStringEnumConverter<AuthenticatorAttachment>))]
17+
#else
1518
[JsonConverter(typeof(FidoEnumConverter<AuthenticatorAttachment>))]
19+
#endif
1620
public enum AuthenticatorAttachment
1721
{
1822
/// <summary>
1923
/// This value indicates platform attachment
2024
/// </summary>
25+
#if NET9_0_OR_GREATER
26+
[JsonStringEnumMemberName("platform")]
27+
#else
2128
[EnumMember(Value = "platform")]
29+
#endif
2230
Platform,
2331

2432
/// <summary>
2533
/// This value indicates cross-platform attachment.
2634
/// </summary>
35+
#if NET9_0_OR_GREATER
36+
[JsonStringEnumMemberName("cross-platform")]
37+
#else
2738
[EnumMember(Value = "cross-platform")]
39+
#endif
2840
CrossPlatform
2941
}

0 commit comments

Comments
 (0)