Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 13 additions & 9 deletions Core/Http/HttpClientAdapter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -137,19 +137,23 @@ private async Task<HttpResponseMessage> ExecuteHttpMethod(Func<Task<HttpResponse

var response = task.Result;

try
if (response.IsSuccessStatusCode)
{
response.EnsureSuccessStatusCode();
return response;
}
catch (HttpRequestException ex)
{
var content = await HttpClientUtils.TryGetContent(response);
_logger.Error(ex, "An error occurred while accessing the source. Content: {content:l}. Exception message: {message:l}", content, ex.Message);

if (response.StatusCode == HttpStatusCode.Unauthorized) throw new UnauthorizedException();
throw;
}
// We don't call EnsureSuccessStatusCode here because it disposes Content
// before throwing, which prevents us from reading the body for the log
var content = await HttpClientUtils.TryGetContent(response);
_logger.Error("An error occurred while accessing the source. Status: {status}. Content: {content:l}",
(int)response.StatusCode, content);

response.Content?.Dispose();

if (response.StatusCode == HttpStatusCode.Unauthorized) throw new UnauthorizedException();

throw new HttpRequestException(
$"Response status code does not indicate success: {(int)response.StatusCode} ({response.ReasonPhrase}).");
}
}
}
11 changes: 11 additions & 0 deletions Extensions/SafeHttpContextAccessorExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System;
using MultiFactor.SelfService.Windows.Portal.Core.Http;
using MultiFactor.SelfService.Windows.Portal.Integrations.Ldap.CredentialVerification;
using MultiFactor.SelfService.Windows.Portal.Core.LdapAttributesCaching;
Expand All @@ -19,6 +20,16 @@ public static CredentialVerificationResult SafeGetCredVerificationResult(this Sa
?? CredentialVerificationResult.CreateBuilder(false).Build();
}

public static void SafeSetCredVerificationResult(this SafeHttpContextAccessor accessor, CredentialVerificationResult result)
{
if (result == null)
{
throw new ArgumentNullException(nameof(result));
}

accessor.HttpContext.Items[Constants.CredentialVerificationResult] = result;
}

public static ILdapAttributesCache SafeGetLdapAttributes(this SafeHttpContextAccessor accessor)
{
return accessor.HttpContext.Items[Constants.LoadedLdapAttributes] as ILdapAttributesCache
Expand Down
3 changes: 3 additions & 0 deletions Integrations/MultifactorIdpApi/MultifactorIdpApi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using MultiFactor.SelfService.Windows.Portal.Integrations.MultiFactorApi.Dto;
using MultiFactor.SelfService.Windows.Portal.Integrations.MultiFactorApi.Exceptions;
using MultiFactor.SelfService.Windows.Portal.Integrations.MultiFactorIdpApi.Dto;
using Serilog;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
Expand Down Expand Up @@ -50,6 +51,7 @@ public async Task<LoginResponseDto> LoginAsync(LoginRequestDto request, Dictiona
}
catch (Exception ex)
{
Log.Logger.Error(ex, "IDP LoginAsync failed");
return LoginResponseDto.Failed(ex.Message);
}
}
Expand Down Expand Up @@ -81,6 +83,7 @@ public async Task<IdentityResponseDto> IdentityAsync(IdentityRequestDto request,
}
catch (Exception ex)
{
Log.Logger.Error(ex, "IDP IdentityAsync failed");
return IdentityResponseDto.Failed(ex.Message);
}
}
Expand Down
1 change: 1 addition & 0 deletions MultiFactor.SelfService.Windows.Portal.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -642,6 +642,7 @@
<Content Include="Views\Account\Authn.cshtml" />
<Content Include="Views\Account\Identity.cshtml" />
<Content Include="Views\Error\AccessDenied.cshtml" />
<Content Include="Views\Error\SessionExpired.cshtml" />
<Content Include="Views\Unlock\Success.cshtml" />
<Content Include="Views\Unlock\Wrong.cshtml" />
<Content Include="Web.config" />
Expand Down
10 changes: 9 additions & 1 deletion Services/TokenValidationService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using MultiFactor.SelfService.Windows.Portal.Services.API;
using Serilog;
using System;
using System.Globalization;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Net;
Expand Down Expand Up @@ -81,7 +82,14 @@ public bool VerifyToken(string jwt, out Token token)
claim.Type == MultiFactorClaims.PasswordExpirationDate);
if (_configuration.NotifyOnPasswordExpirationDaysLeft > 0 && passwordExpirationDate?.Value != null)
{
token.PasswordExpirationDate = DateTime.Parse(passwordExpirationDate.Value);
if (DateTime.TryParse(passwordExpirationDate.Value, CultureInfo.InvariantCulture, DateTimeStyles.None, out var parsed))
{
token.PasswordExpirationDate = parsed;
}
else
{
_logger.Warning("Failed to parse passwordExpirationDate claim value '{Value}'", passwordExpirationDate.Value);
}
}

return true; //token valid
Expand Down
10 changes: 8 additions & 2 deletions Stories/SignIn/ClaimsSources/MultiFactorClaimsSource.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using MultiFactor.SelfService.Windows.Portal.Core.Authentication.AuthenticationClaims;
Expand Down Expand Up @@ -30,8 +31,13 @@ public IReadOnlyDictionary<string, string> GetClaims()
return claims;
}

claims.Add(MultiFactorClaims.PasswordExpirationDate,
result.PasswordExpirationDate.ToString(CultureInfo.InvariantCulture));

if (result.PasswordExpirationDate > DateTime.MinValue
&& result.PasswordExpirationDate < DateTime.MaxValue)
{
claims.Add(MultiFactorClaims.PasswordExpirationDate,
result.PasswordExpirationDate.ToString(CultureInfo.InvariantCulture));
}

return claims;
}
Expand Down
2 changes: 2 additions & 0 deletions Stories/SignIn/IdentityStory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@ public async Task<ActionResult> ExecuteAsync(IdentityModel model, Dictionary<str

_logger.Information("User '{User}' membership verified successfully", username);
verifiedMembership = MapToVerifiedMembershipDto(membershipResult);

_contextAccessor.SafeSetCredVerificationResult(membershipResult);
}

var authenticators = await _multifactorApiClient.GetUserAuthenticatorsAsync(username);
Expand Down
2 changes: 2 additions & 0 deletions Stories/SignIn/SignInStory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@ public async Task<ActionResult> ExecuteAsync(LoginModel model, Dictionary<string

_logger.Information("User '{User}' credentials verified successfully", username);

_contextAccessor.SafeSetCredVerificationResult(credentialResult);

var claims = _claimsProvider.GetClaims().ToDictionary(x => x.Key, x => x.Value);
claims.Add(AuthenticationClaims.AUTHENTICATION_METHODS_REFERENCES, AuthenticationClaims.PASSWORD_METHOD);

Expand Down