Skip to content

Commit 5a3b95d

Browse files
committed
Add metrics to Identity
1 parent 1eda538 commit 5a3b95d

File tree

14 files changed

+1852
-275
lines changed

14 files changed

+1852
-275
lines changed

src/Http/Authentication.Abstractions/src/IAuthenticationService.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ public interface IAuthenticationService
4040
Task ForbidAsync(HttpContext context, string? scheme, AuthenticationProperties? properties);
4141

4242
/// <summary>
43-
/// Sign a principal in for the specified authentication scheme.
43+
/// Sign in a principal in for the specified authentication scheme.
4444
/// </summary>
4545
/// <param name="context">The <see cref="HttpContext"/>.</param>
4646
/// <param name="scheme">The name of the authentication scheme.</param>

src/Http/Authentication.Core/src/AuthenticationService.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ public virtual async Task ForbidAsync(HttpContext context, string? scheme, Authe
145145
}
146146

147147
/// <summary>
148-
/// Sign a principal in for the specified authentication scheme.
148+
/// Sign in a principal in for the specified authentication scheme.
149149
/// </summary>
150150
/// <param name="context">The <see cref="HttpContext"/>.</param>
151151
/// <param name="scheme">The name of the authentication scheme.</param>

src/Identity/Core/src/Microsoft.AspNetCore.Identity.csproj

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@
1313
</PropertyGroup>
1414

1515
<ItemGroup>
16-
<Compile Include="$(SharedSourceRoot)DefaultMessageEmailSender.cs" />
16+
<Compile Include="$(SharedSourceRoot)DefaultMessageEmailSender.cs" LinkBase="Shared" />
17+
<Compile Include="$(SharedSourceRoot)Metrics\MetricsConstants.cs" LinkBase="Shared" />
1718
</ItemGroup>
1819

1920
<ItemGroup>

src/Identity/Core/src/SignInManager.cs

Lines changed: 184 additions & 34 deletions
Large diffs are not rendered by default.
Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System.Diagnostics;
5+
using System.Diagnostics.Metrics;
6+
7+
namespace Microsoft.AspNetCore.Identity;
8+
9+
internal sealed class SignInManagerMetrics : IDisposable
10+
{
11+
public const string MeterName = "Microsoft.AspNetCore.Identity";
12+
13+
public const string AuthenticateCounterName = "aspnetcore.identity.sign_in.authenticate";
14+
public const string RememberTwoFactorCounterName = "aspnetcore.identity.sign_in.remember_two_factor";
15+
public const string ForgetTwoFactorCounterName = "aspnetcore.identity.sign_in.forget_two_factor";
16+
public const string RefreshCounterName = "aspnetcore.identity.sign_in.refresh";
17+
public const string CheckPasswordCounterName = "aspnetcore.identity.sign_in.check_password";
18+
public const string SignInUserPrincipalCounterName = "aspnetcore.identity.sign_in.sign_in_principal";
19+
public const string SignOutUserPrincipalCounterName = "aspnetcore.identity.sign_in.sign_out_principal";
20+
21+
private readonly Meter _meter;
22+
private readonly Counter<long> _authenticateCounter;
23+
private readonly Counter<long> _rememberTwoFactorClientCounter;
24+
private readonly Counter<long> _forgetTwoFactorCounter;
25+
private readonly Counter<long> _refreshCounter;
26+
private readonly Counter<long> _checkPasswordCounter;
27+
private readonly Counter<long> _signInUserPrincipalCounter;
28+
private readonly Counter<long> _signOutUserPrincipalCounter;
29+
30+
public SignInManagerMetrics(IMeterFactory meterFactory)
31+
{
32+
_meter = meterFactory.Create(MeterName);
33+
34+
_authenticateCounter = _meter.CreateCounter<long>(AuthenticateCounterName, "count", "The number of authenticate and sign in attempts.");
35+
_rememberTwoFactorClientCounter = _meter.CreateCounter<long>(RememberTwoFactorCounterName, "count", "The number of two factor clients remembered.");
36+
_forgetTwoFactorCounter = _meter.CreateCounter<long>(ForgetTwoFactorCounterName, "count", "The number of two factor clients forgotten.");
37+
_refreshCounter = _meter.CreateCounter<long>(RefreshCounterName, "count", "The number of refresh sign-in attempts.");
38+
_checkPasswordCounter = _meter.CreateCounter<long>(CheckPasswordCounterName, "count", "The number of check password attempts.");
39+
_signInUserPrincipalCounter = _meter.CreateCounter<long>(SignInUserPrincipalCounterName, "count", "The number of user principals signed in.");
40+
_signOutUserPrincipalCounter = _meter.CreateCounter<long>(SignOutUserPrincipalCounterName, "count", "The number of user principals signed out.");
41+
}
42+
43+
internal void CheckPasswordSignIn(string userType, SignInResult? result, Exception? exception = null)
44+
{
45+
var tags = new TagList
46+
{
47+
{ "aspnetcore.identity.user_type", userType },
48+
};
49+
AddSignInResult(ref tags, result);
50+
AddExceptionTags(ref tags, exception);
51+
52+
_checkPasswordCounter.Add(1, tags);
53+
}
54+
55+
internal void AuthenticateSignIn(string userType, string authenticationScheme, SignInResult? result, SignInType signInType, bool isPersistent, Exception? exception = null)
56+
{
57+
var tags = new TagList
58+
{
59+
{ "aspnetcore.identity.user_type", userType },
60+
{ "aspnetcore.identity.authentication_scheme", authenticationScheme },
61+
{ "aspnetcore.identity.sign_in.type", GetSignInType(signInType) },
62+
{ "aspnetcore.identity.sign_in.is_persistent", isPersistent },
63+
};
64+
if (result != null)
65+
{
66+
tags.Add("aspnetcore.identity.sign_in.result", GetSignInResult(result));
67+
}
68+
AddExceptionTags(ref tags, exception);
69+
70+
_authenticateCounter.Add(1, tags);
71+
}
72+
73+
internal void SignInUserPrincipal(string userType, string authenticationScheme, Exception? exception = null)
74+
{
75+
var tags = new TagList
76+
{
77+
{ "aspnetcore.identity.user_type", userType },
78+
{ "aspnetcore.identity.authentication_scheme", authenticationScheme },
79+
};
80+
AddExceptionTags(ref tags, exception);
81+
82+
_signInUserPrincipalCounter.Add(1, tags);
83+
}
84+
85+
internal void SignOutUserPrincipal(string userType, string authenticationScheme, Exception? exception = null)
86+
{
87+
var tags = new TagList
88+
{
89+
{ "aspnetcore.identity.user_type", userType },
90+
{ "aspnetcore.identity.authentication_scheme", authenticationScheme },
91+
};
92+
AddExceptionTags(ref tags, exception);
93+
94+
_signOutUserPrincipalCounter.Add(1, tags);
95+
}
96+
97+
internal void RememberTwoFactorClient(string userType, string authenticationScheme, Exception? exception = null)
98+
{
99+
var tags = new TagList
100+
{
101+
{ "aspnetcore.identity.user_type", userType },
102+
{ "aspnetcore.identity.authentication_scheme", authenticationScheme }
103+
};
104+
AddExceptionTags(ref tags, exception);
105+
106+
_rememberTwoFactorClientCounter.Add(1, tags);
107+
}
108+
109+
internal void ForgetTwoFactorClient(string userType, string authenticationScheme, Exception? exception = null)
110+
{
111+
var tags = new TagList
112+
{
113+
{ "aspnetcore.identity.user_type", userType },
114+
{ "aspnetcore.identity.authentication_scheme", authenticationScheme }
115+
};
116+
AddExceptionTags(ref tags, exception);
117+
118+
_forgetTwoFactorCounter.Add(1, tags);
119+
}
120+
121+
internal void RefreshSignIn(string userType, string authenticationScheme, bool? success, bool? isPersistent, Exception? exception = null)
122+
{
123+
var tags = new TagList
124+
{
125+
{ "aspnetcore.identity.user_type", userType },
126+
{ "aspnetcore.identity.authentication_scheme", authenticationScheme },
127+
{ "aspnetcore.identity.sign_in.result", success.GetValueOrDefault() ? "success" : "failure" }
128+
};
129+
if (isPersistent != null)
130+
{
131+
tags.Add("aspnetcore.identity.sign_in.is_persistent", isPersistent.Value);
132+
}
133+
AddExceptionTags(ref tags, exception);
134+
135+
_refreshCounter.Add(1, tags);
136+
}
137+
138+
public void Dispose()
139+
{
140+
_meter.Dispose();
141+
}
142+
143+
private static void AddSignInResult(ref TagList tags, SignInResult? result)
144+
{
145+
if (result != null)
146+
{
147+
tags.Add("aspnetcore.identity.sign_in.result", GetSignInResult(result));
148+
}
149+
}
150+
151+
private static void AddExceptionTags(ref TagList tags, Exception? exception)
152+
{
153+
if (exception != null)
154+
{
155+
tags.Add("error.type", exception.GetType().FullName!);
156+
}
157+
}
158+
159+
private static string GetSignInType(SignInType signInType)
160+
{
161+
return signInType switch
162+
{
163+
SignInType.Password => "password",
164+
SignInType.TwoFactorRecoveryCode => "two_factor_recovery_code",
165+
SignInType.TwoFactorAuthenticator => "two_factor_authenticator",
166+
SignInType.TwoFactor => "two_factor",
167+
SignInType.External => "external",
168+
_ => "_UNKNOWN"
169+
};
170+
}
171+
172+
private static string GetSignInResult(SignInResult result)
173+
{
174+
return result switch
175+
{
176+
{ Succeeded: true } => "success",
177+
{ IsLockedOut: true } => "locked_out",
178+
{ IsNotAllowed: true } => "not_allowed",
179+
{ RequiresTwoFactor: true } => "requires_two_factor",
180+
_ => "failure"
181+
};
182+
}
183+
}
184+
185+
internal enum SignInType
186+
{
187+
Password,
188+
TwoFactorRecoveryCode,
189+
TwoFactorAuthenticator,
190+
TwoFactor,
191+
External
192+
}

src/Identity/Extensions.Core/src/PublicAPI.Unshipped.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,3 +55,4 @@ virtual Microsoft.AspNetCore.Identity.UserManager<TUser>.GetPasskeysAsync(TUser!
5555
virtual Microsoft.AspNetCore.Identity.UserManager<TUser>.RemovePasskeyAsync(TUser! user, byte[]! credentialId) -> System.Threading.Tasks.Task<Microsoft.AspNetCore.Identity.IdentityResult!>!
5656
virtual Microsoft.AspNetCore.Identity.UserManager<TUser>.SetPasskeyAsync(TUser! user, Microsoft.AspNetCore.Identity.UserPasskeyInfo! passkey) -> System.Threading.Tasks.Task<Microsoft.AspNetCore.Identity.IdentityResult!>!
5757
virtual Microsoft.AspNetCore.Identity.UserManager<TUser>.SupportsUserPasskey.get -> bool
58+
Microsoft.AspNetCore.Identity.UserManager<TUser>.ServiceProvider.get -> System.IServiceProvider!

0 commit comments

Comments
 (0)