diff --git a/src/Duende.Bff.EntityFramework/Store/UserSessionStore.cs b/src/Duende.Bff.EntityFramework/Store/UserSessionStore.cs
index 09ce1554..5e88b201 100644
--- a/src/Duende.Bff.EntityFramework/Store/UserSessionStore.cs
+++ b/src/Duende.Bff.EntityFramework/Store/UserSessionStore.cs
@@ -40,6 +40,8 @@ public UserSessionStore(IOptions
options, ISessionDbConte
///
public async Task CreateUserSessionAsync(UserSession session, CancellationToken cancellationToken)
{
+ _logger.LogDebug("Creating user session record in store for sub {sub} sid {sid}", session.SubjectId, session.SessionId);
+
var item = new UserSessionEntity()
{
ApplicationName = _applicationDiscriminator
@@ -65,6 +67,8 @@ public async Task DeleteUserSessionAsync(string key, CancellationToken cancellat
if (item != null)
{
+ _logger.LogDebug("Deleting user session record in store for sub {sub} sid {sid}", item.SubjectId, item.SessionId);
+
_sessionDbContext.UserSessions.Remove(item);
try
{
@@ -114,6 +118,8 @@ public async Task DeleteUserSessionsAsync(UserSessionsFilter filter, Cancellatio
items = items.Where(x => x.SessionId == filter.SessionId).ToArray();
}
+ _logger.LogDebug("Deleting {count} user session(s) from store for sub {sub} sid {sid}", items.Length, filter.SubjectId, filter.SessionId);
+
_sessionDbContext.UserSessions.RemoveRange(items);
try
@@ -143,6 +149,8 @@ public async Task GetUserSessionAsync(string key, CancellationToken
UserSession result = null;
if (item != null)
{
+ _logger.LogDebug("Getting user session record from store for sub {sub} sid {sid}", item.SubjectId, item.SessionId);
+
result = new UserSession();
item.CopyTo(result);
}
@@ -179,12 +187,16 @@ public async Task> GetUserSessionsAsync(UserSes
items = items.Where(x => x.SessionId == filter.SessionId).ToArray();
}
- return items.Select(x =>
+ var results = items.Select(x =>
{
var item = new UserSession();
x.CopyTo(item);
return item;
}).ToArray();
+
+ _logger.LogDebug("Getting {count} user session(s) from store for sub {sub} sid {sid}", results.Length, filter.SubjectId, filter.SessionId);
+
+ return results;
}
///
@@ -194,6 +206,8 @@ public async Task UpdateUserSessionAsync(string key, UserSessionUpdate session,
var item = items.SingleOrDefault(x => x.Key == key && x.ApplicationName == _applicationDiscriminator);
if (item != null)
{
+ _logger.LogDebug("Updating user session record in store for sub {sub} sid {sid}", item.SubjectId, item.SessionId);
+
session.CopyTo(item);
await _sessionDbContext.SaveChangesAsync(cancellationToken);
}
diff --git a/src/Duende.Bff/EndpointServices/BackchannelLogout/DefaultBackchannelLogoutService.cs b/src/Duende.Bff/EndpointServices/BackchannelLogout/DefaultBackchannelLogoutService.cs
index dbebc532..7a05c0fd 100644
--- a/src/Duende.Bff/EndpointServices/BackchannelLogout/DefaultBackchannelLogoutService.cs
+++ b/src/Duende.Bff/EndpointServices/BackchannelLogout/DefaultBackchannelLogoutService.cs
@@ -66,6 +66,8 @@ public DefaultBackchannelLogoutService(
///
public virtual async Task ProcessRequestAsync(HttpContext context)
{
+ Logger.LogDebug("Processing back-channel logout request");
+
context.Response.Headers.Add("Cache-Control", "no-cache, no-store");
context.Response.Headers.Add("Pragma", "no-cache");
@@ -120,8 +122,13 @@ await UserSession.RevokeSessionsAsync(new UserSessionsFilter
var claims = await ValidateJwt(logoutToken);
if (claims == null)
{
+ Logger.LogDebug("No claims in back-channel JWT");
return null;
}
+ else
+ {
+ Logger.LogTrace("Claims found in back-channel JWT {claims}", claims.Claims);
+ }
if (claims.FindFirst("sub") == null && claims.FindFirst("sid") == null)
{
@@ -174,6 +181,7 @@ await UserSession.RevokeSessionsAsync(new UserSessionsFilter
var result = handler.ValidateToken(jwt, parameters);
if (result.IsValid)
{
+ Logger.LogDebug("Back-channel JWT validation successful");
return result.ClaimsIdentity;
}
diff --git a/src/Duende.Bff/EndpointServices/Login/DefaultLoginService.cs b/src/Duende.Bff/EndpointServices/Login/DefaultLoginService.cs
index 10710671..3e55a009 100644
--- a/src/Duende.Bff/EndpointServices/Login/DefaultLoginService.cs
+++ b/src/Duende.Bff/EndpointServices/Login/DefaultLoginService.cs
@@ -3,6 +3,7 @@
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Http;
+using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using System;
using System.Linq;
@@ -19,26 +20,35 @@ public class DefaultLoginService : ILoginService
/// The BFF options
///
protected readonly BffOptions Options;
-
+
///
/// The return URL validator
///
protected readonly IReturnUrlValidator ReturnUrlValidator;
+
+ ///
+ /// The logger
+ ///
+ protected readonly ILogger Logger;
///
/// ctor
///
///
///
- public DefaultLoginService(IOptions options, IReturnUrlValidator returnUrlValidator)
+ ///
+ public DefaultLoginService(IOptions options, IReturnUrlValidator returnUrlValidator, ILogger logger)
{
Options = options.Value;
ReturnUrlValidator = returnUrlValidator;
+ Logger = logger;
}
///
public virtual async Task ProcessRequestAsync(HttpContext context)
{
+ Logger.LogDebug("Processing login request");
+
context.CheckForBffMiddleware(Options);
var returnUrl = context.Request.Query[Constants.RequestParameters.ReturnUrl].FirstOrDefault();
@@ -68,6 +78,8 @@ public virtual async Task ProcessRequestAsync(HttpContext context)
RedirectUri = returnUrl
};
+ Logger.LogDebug("Login endpoint triggering Challenge with returnUrl {returnUrl}", returnUrl);
+
await context.ChallengeAsync(props);
}
}
\ No newline at end of file
diff --git a/src/Duende.Bff/EndpointServices/Logout/DefaultLogoutService.cs b/src/Duende.Bff/EndpointServices/Logout/DefaultLogoutService.cs
index 352eae2b..2043b1e4 100644
--- a/src/Duende.Bff/EndpointServices/Logout/DefaultLogoutService.cs
+++ b/src/Duende.Bff/EndpointServices/Logout/DefaultLogoutService.cs
@@ -4,6 +4,7 @@
using IdentityModel;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Http;
+using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using System;
using System.Linq;
@@ -30,6 +31,11 @@ public class DefaultLogoutService : ILogoutService
/// The return URL validator
///
protected readonly IReturnUrlValidator ReturnUrlValidator;
+
+ ///
+ /// The logger
+ ///
+ protected readonly ILogger Logger;
///
/// Ctor
@@ -37,16 +43,23 @@ public class DefaultLogoutService : ILogoutService
///
///
///
- public DefaultLogoutService(IOptions options, IAuthenticationSchemeProvider authenticationAuthenticationSchemeProviderProvider, IReturnUrlValidator returnUrlValidator)
+ ///
+ public DefaultLogoutService(IOptions options,
+ IAuthenticationSchemeProvider authenticationAuthenticationSchemeProviderProvider,
+ IReturnUrlValidator returnUrlValidator,
+ ILogger logger)
{
Options = options.Value;
AuthenticationSchemeProvider = authenticationAuthenticationSchemeProviderProvider;
ReturnUrlValidator = returnUrlValidator;
+ Logger = logger;
}
///
public virtual async Task ProcessRequestAsync(HttpContext context)
{
+ Logger.LogDebug("Processing logout request");
+
context.CheckForBffMiddleware(Options);
var result = await context.AuthenticateAsync();
@@ -66,12 +79,7 @@ public virtual async Task ProcessRequestAsync(HttpContext context)
}
}
- // get rid of local cookie first
- var signInScheme = await AuthenticationSchemeProvider.GetDefaultSignInSchemeAsync();
- await context.SignOutAsync(signInScheme?.Name);
-
var returnUrl = context.Request.Query[Constants.RequestParameters.ReturnUrl].FirstOrDefault();
-
if (!string.IsNullOrWhiteSpace(returnUrl))
{
if (!await ReturnUrlValidator.IsValidAsync(returnUrl))
@@ -80,6 +88,10 @@ public virtual async Task ProcessRequestAsync(HttpContext context)
}
}
+ // get rid of local cookie first
+ var signInScheme = await AuthenticationSchemeProvider.GetDefaultSignInSchemeAsync();
+ await context.SignOutAsync(signInScheme?.Name);
+
if (String.IsNullOrWhiteSpace(returnUrl))
{
if (context.Request.PathBase.HasValue)
@@ -97,6 +109,8 @@ public virtual async Task ProcessRequestAsync(HttpContext context)
RedirectUri = returnUrl
};
+ Logger.LogDebug("Logout endpoint triggering SignOut with returnUrl {returnUrl}", returnUrl);
+
// trigger idp logout
await context.SignOutAsync(props);
}
diff --git a/src/Duende.Bff/EndpointServices/SilentLogin/DefaultSilentLoginCallbackService.cs b/src/Duende.Bff/EndpointServices/SilentLogin/DefaultSilentLoginCallbackService.cs
index 010a8e99..e29f274d 100644
--- a/src/Duende.Bff/EndpointServices/SilentLogin/DefaultSilentLoginCallbackService.cs
+++ b/src/Duende.Bff/EndpointServices/SilentLogin/DefaultSilentLoginCallbackService.cs
@@ -4,6 +4,7 @@
using IdentityModel;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Http;
+using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using System.Text;
using System.Threading.Tasks;
@@ -15,21 +16,33 @@ namespace Duende.Bff;
///
public class DefaultSilentLoginCallbackService : ISilentLoginCallbackService
{
- private readonly BffOptions _options;
+ ///
+ /// The BFF options
+ ///
+ protected readonly BffOptions Options;
+
+ ///
+ /// The logger
+ ///
+ protected readonly ILogger Logger;
///
/// ctor
///
///
- public DefaultSilentLoginCallbackService(IOptions options)
+ ///
+ public DefaultSilentLoginCallbackService(IOptions options, ILogger logger)
{
- _options = options.Value;
+ Options = options.Value;
+ Logger = logger;
}
///
- public async Task ProcessRequestAsync(HttpContext context)
+ public virtual async Task ProcessRequestAsync(HttpContext context)
{
- context.CheckForBffMiddleware(_options);
+ Logger.LogDebug("Processing silent login callback request");
+
+ context.CheckForBffMiddleware(Options);
var result = (await context.AuthenticateAsync()).Succeeded ? "true" : "false";
var json = $"{{source:'bff-silent-login', isLoggedIn:{result}}}";
@@ -46,6 +59,8 @@ public async Task ProcessRequestAsync(HttpContext context)
context.Response.Headers["Cache-Control"] = "no-store, no-cache, max-age=0";
context.Response.Headers["Pragma"] = "no-cache";
+ Logger.LogDebug("Silent login endpoint rendering HTML with JS postMessage to origin {origin} with isLoggedIn {isLoggedIn}", origin, result);
+
await context.Response.WriteAsync(html, Encoding.UTF8);
}
}
\ No newline at end of file
diff --git a/src/Duende.Bff/EndpointServices/SilentLogin/DefaultSilentLoginService.cs b/src/Duende.Bff/EndpointServices/SilentLogin/DefaultSilentLoginService.cs
index be5eb216..514827b1 100644
--- a/src/Duende.Bff/EndpointServices/SilentLogin/DefaultSilentLoginService.cs
+++ b/src/Duende.Bff/EndpointServices/SilentLogin/DefaultSilentLoginService.cs
@@ -3,6 +3,7 @@
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Http;
+using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using System.Threading.Tasks;
@@ -13,24 +14,36 @@ namespace Duende.Bff;
///
public class DefaultSilentLoginService : ISilentLoginService
{
- private readonly BffOptions _options;
+ ///
+ /// The BFF options
+ ///
+ protected readonly BffOptions Options;
+
+ ///
+ /// The logger
+ ///
+ protected readonly ILogger Logger;
///
/// ctor
///
///
- public DefaultSilentLoginService(IOptions options)
+ ///
+ public DefaultSilentLoginService(IOptions options, ILogger logger)
{
- _options = options.Value;
+ Options = options.Value;
+ Logger = logger;
}
///
- public async Task ProcessRequestAsync(HttpContext context)
+ public virtual async Task ProcessRequestAsync(HttpContext context)
{
- context.CheckForBffMiddleware(_options);
+ Logger.LogDebug("Processing silent login request");
+
+ context.CheckForBffMiddleware(Options);
var pathBase = context.Request.PathBase;
- var redirectPath = pathBase + _options.SilentLoginCallbackPath;
+ var redirectPath = pathBase + Options.SilentLoginCallbackPath;
var props = new AuthenticationProperties
{
@@ -41,6 +54,8 @@ public async Task ProcessRequestAsync(HttpContext context)
},
};
+ Logger.LogDebug("Silent login endpoint triggering Challenge with returnUrl {redirectUri}", redirectPath);
+
await context.ChallengeAsync(props);
}
}
\ No newline at end of file
diff --git a/src/Duende.Bff/EndpointServices/User/DefaultUserService.cs b/src/Duende.Bff/EndpointServices/User/DefaultUserService.cs
index 990a572b..105dbc32 100644
--- a/src/Duende.Bff/EndpointServices/User/DefaultUserService.cs
+++ b/src/Duende.Bff/EndpointServices/User/DefaultUserService.cs
@@ -47,6 +47,8 @@ public DefaultUserService(IOptions options, ILoggerFactory loggerFac
///
public virtual async Task ProcessRequestAsync(HttpContext context)
{
+ Logger.LogDebug("Processing user request");
+
context.CheckForBffMiddleware(Options);
var result = await context.AuthenticateAsync();
@@ -63,6 +65,8 @@ public virtual async Task ProcessRequestAsync(HttpContext context)
{
context.Response.StatusCode = 401;
}
+
+ Logger.LogDebug("User endpoint indicates the user is not logged in, using status code {code}", context.Response.StatusCode);
}
else
{
@@ -75,6 +79,8 @@ public virtual async Task ProcessRequestAsync(HttpContext context)
context.Response.StatusCode = 200;
context.Response.ContentType = "application/json";
await context.Response.WriteAsync(json, Encoding.UTF8);
+
+ Logger.LogTrace("User endpoint indicates the user is logged in with claims {claims}", claims);
}
}
diff --git a/src/Duende.Bff/SessionManagement/Revocation/SessionRevocationService.cs b/src/Duende.Bff/SessionManagement/Revocation/SessionRevocationService.cs
index 621d1fd9..369acc85 100644
--- a/src/Duende.Bff/SessionManagement/Revocation/SessionRevocationService.cs
+++ b/src/Duende.Bff/SessionManagement/Revocation/SessionRevocationService.cs
@@ -48,6 +48,8 @@ public async Task RevokeSessionsAsync(UserSessionsFilter filter, CancellationTok
filter.SessionId = null;
}
+ _logger.LogDebug("Revoking sessions for sub {sub} and sid {sid}", filter.SubjectId, filter.SessionId);
+
if (_options.RevokeRefreshTokenOnLogout)
{
var tickets = await _ticketStore.GetUserTicketsAsync(filter);
@@ -59,15 +61,8 @@ public async Task RevokeSessionsAsync(UserSessionsFilter filter, CancellationTok
if (!String.IsNullOrWhiteSpace(refreshToken))
{
await _tokenEndpoint.RevokeRefreshTokenAsync(refreshToken, new UserTokenRequestParameters(), cancellationToken);
- // todo: no more error response - is logging required?
- // if (response.IsError)
- // {
- // _logger.LogDebug("Error revoking refresh token: {error} for subject id: {sub} and session id: {sid}", response.Error, ticket.GetSubjectId(), ticket.GetSessionId());
- // }
- // else
- // {
- // _logger.LogDebug("Refresh token revoked successfully for subject id: {sub} and session id: {sid}", ticket.GetSubjectId(), ticket.GetSessionId());
- // }
+
+ _logger.LogDebug("Refresh token revoked for sub {sub} and sid {sid}", ticket.GetSubjectId(), ticket.GetSessionId());
}
}
}
diff --git a/src/Duende.Bff/SessionManagement/TicketStore/ServerSideTicketStore.cs b/src/Duende.Bff/SessionManagement/TicketStore/ServerSideTicketStore.cs
index d1a741b6..dfd3fadb 100644
--- a/src/Duende.Bff/SessionManagement/TicketStore/ServerSideTicketStore.cs
+++ b/src/Duende.Bff/SessionManagement/TicketStore/ServerSideTicketStore.cs
@@ -10,6 +10,7 @@
using IdentityModel;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.DataProtection;
+using Microsoft.AspNetCore.DataProtection.KeyManagement;
using Microsoft.Extensions.Logging;
namespace Duende.Bff;
@@ -141,6 +142,8 @@ public Task RemoveAsync(string key)
///
public async Task> GetUserTicketsAsync(UserSessionsFilter filter, CancellationToken cancellationToken)
{
+ _logger.LogDebug("Getting AuthenticationTickets from store for sub {sub} sid {sid}", filter.SubjectId, filter.SessionId);
+
var list = new List();
var sessions = await _store.GetUserSessionsAsync(filter, cancellationToken);