ABP Commercial 7.4.2 / Blazor Server / EF / Non tiered / Separate Host and Tenant DBs / Lepton Theme
Hi, We have extended identityuser to include several new properties to determine if certain application specific email notifications are turned on for the users 'my account' area.
We then successfully added a new 'Email Notifications' profile group under the 'my account' area (see last image below).
A new model NotificationsInfoModel
is declared in our GroupViewComponent
for notifications and this model is used in our default.cshtml page for notifications.
Our default.cshtml page is defined as follows...
@model FM.nVision.Blazor.Pages.Account.Components.ProfileManagementGroup.Notifications.AccountProfileNotificationsGroupViewComponent.NotificationsInfoModel
<form id="NotificationsForm">
<div class="mb-3">
<h4 class="pt-2 pb-3">@L["Time Off Requests"]</h4>
<abp-row class="pb-4">
<abp-column>
<div>Submit Confirmation</div>
<div class="text-subtle">Occurs every time you submit a time off request</div>
</abp-column>
<abp-column>
<div class="form-switch ps-2">
<abp-input asp-for="NotifyTimeOffRequestSubmit" class="mb-4" />
</div>
</abp-column>
</abp-row>
...
</div>
<abp-button type="submit" button-type="Primary" text="@L["Submit"].Value" />
</form>
Our question is how do we handle the server side action that is performed when the submit button is clicked? We looked at the abp implementation of 'Personal Info', 'Change Password', etc. but we can't determine what gets executed when the submit button gets clicked. What makes that determination? We are not that familiar with MVC as we are building a Blazor Server application.
We essentially want to call an new method to an overridden ProfileAppService that contains a new method to save email notification preferences.
Any guidance is greatly appreciated. Thank you.
Hi liangshiwei,
Thank you for the guidance. I'll be giving your approach a try...
ABP Commercial 7.4.2 / Blazor Server / EF / Non tiered / Separate Host and Tenant DBs / Lepton Theme
Hi,
We recently had our ABP application penetration tested by an established security firm. The testers noted the following...
The application allows users to authenticate with a multi-factor authentication code sent via email or cellphone. There are two primary issues with the MFA authentication workflow: -There are no limits to the number of MFA guesses a user can make as long as guesses are made using the API -MFA tokens only expire after the time limit of 6 minutes has elapsed, not when a new MFA token is generated or when the token is used to login Together these misconfigurations can make it so that an MFA bypass is statistically probable....
They end with the following recommendation...
Ensure that MFA codes are invalidated after being used to authenticate a user. Furthermore, ensure that a user can only guess the MFA code a small number of times (5-10) before a lockout
How can we override/adjust the application to expire the security code/token as soon as it is used to login? Additionally, how can we make it such that after x failed attempts, the security code/token is expired?
Any suggestions/guidance is greatly appreciated as we need to have the application certified by this security firm.
Regards,
Brian
Hi liangshiwei,
It appears the user was changing their password with the failed validation "Volo.Abp.Identity:PasswordRequiresNonAlphanumeric", yet they received the following message from abp.jquery.js.
defaultError403: {
message: 'You are not authorized!',
details: 'You are not allowed to perform this operation.'
},
We are unfamiliar with the internal jquery implementation within ABP.
Please see below for the log details and advise.
https://eiufsd.nvisiononline.net/api/account/my-profile/change-password application/json 99
2024-05-03 13:49:07.331 +00:00 [INF] (Instance: 53d7) Executing endpoint 'Volo.Abp.Account.ProfileController.ChangePasswordAsync (Volo.Abp.Account.Pro.Public.HttpApi)'
2024-05-03 13:49:07.335 +00:00 [INF] (Instance: 53d7) Route matched with {controller = "Profile", area = "account", action = "ChangePassword", page = ""}. Executing controller action with signature System.Threading.Tasks.Task ChangePasswordAsync(Volo.Abp.Account.ChangePasswordInput) on controller Volo.Abp.Account.ProfileController (Volo.Abp.Account.Pro.Public.HttpApi).
2024-05-03 13:49:07.351 +00:00 [INF] (Instance: 53d7) Executing action method Volo.Abp.Account.ProfileController.ChangePasswordAsync (Volo.Abp.Account.Pro.Public.HttpApi) - Validation state: "Valid"
2024-05-03 13:49:07.572 +00:00 [WRN] (Instance: 53d7) ---------- RemoteServiceErrorInfo ----------
{
"code": "Volo.Abp.Identity:PasswordRequiresNonAlphanumeric",
"message": "Passwords must have at least one non alphanumeric character.",
"details": null,
"data": {},
"validationErrors": null
}
2024-05-03 13:49:07.572 +00:00 [WRN] (Instance: 53d7) Passwords must have at least one non alphanumeric character.
Volo.Abp.Identity.AbpIdentityResultException: Passwords must have at least one non alphanumeric character.
at Microsoft.AspNetCore.Identity.AbpIdentityResultExtensions.CheckErrors(IdentityResult identityResult)
at Volo.Abp.Account.ProfileAppService.ChangePasswordAsync(ChangePasswordInput input)
at Castle.DynamicProxy.AsyncInterceptorBase.ProceedAsynchronous(IInvocation invocation, IInvocationProceedInfo proceedInfo)
at Volo.Abp.Castle.DynamicProxy.CastleAbpMethodInvocationAdapter.ProceedAsync()
at Volo.Abp.Authorization.AuthorizationInterceptor.InterceptAsync(IAbpMethodInvocation invocation)
at Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter`1.InterceptAsync(IInvocation invocation, IInvocationProceedInfo proceedInfo, Func`3 proceed)
at Castle.DynamicProxy.AsyncInterceptorBase.ProceedAsynchronous(IInvocation invocation, IInvocationProceedInfo proceedInfo)
at Volo.Abp.Castle.DynamicProxy.CastleAbpMethodInvocationAdapter.ProceedAsync()
at Volo.Abp.GlobalFeatures.GlobalFeatureInterceptor.InterceptAsync(IAbpMethodInvocation invocation)
at Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter`1.InterceptAsync(IInvocation invocation, IInvocationProceedInfo proceedInfo, Func`3 proceed)
at Castle.DynamicProxy.AsyncInterceptorBase.ProceedAsynchronous(IInvocation invocation, IInvocationProceedInfo proceedInfo)
at Volo.Abp.Castle.DynamicProxy.CastleAbpMethodInvocationAdapter.ProceedAsync()
at Volo.Abp.Auditing.AuditingInterceptor.ProceedByLoggingAsync(IAbpMethodInvocation invocation, AbpAuditingOptions options, IAuditingHelper auditingHelper, IAuditLogScope auditLogScope)
at Volo.Abp.Auditing.AuditingInterceptor.InterceptAsync(IAbpMethodInvocation invocation)
at Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter`1.InterceptAsync(IInvocation invocation, IInvocationProceedInfo proceedInfo, Func`3 proceed)
at Castle.DynamicProxy.AsyncInterceptorBase.ProceedAsynchronous(IInvocation invocation, IInvocationProceedInfo proceedInfo)
at Volo.Abp.Castle.DynamicProxy.CastleAbpMethodInvocationAdapter.ProceedAsync()
at Volo.Abp.Features.FeatureInterceptor.InterceptAsync(IAbpMethodInvocation invocation)
at Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter`1.InterceptAsync(IInvocation invocation, IInvocationProceedInfo proceedInfo, Func`3 proceed)
at Castle.DynamicProxy.AsyncInterceptorBase.ProceedAsynchronous(IInvocation invocation, IInvocationProceedInfo proceedInfo)
at Volo.Abp.Castle.DynamicProxy.CastleAbpMethodInvocationAdapter.ProceedAsync()
at Volo.Abp.Validation.ValidationInterceptor.InterceptAsync(IAbpMethodInvocation invocation)
at Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter`1.InterceptAsync(IInvocation invocation, IInvocationProceedInfo proceedInfo, Func`3 proceed)
at Castle.DynamicProxy.AsyncInterceptorBase.ProceedAsynchronous(IInvocation invocation, IInvocationProceedInfo proceedInfo)
at Volo.Abp.Castle.DynamicProxy.CastleAbpMethodInvocationAdapter.ProceedAsync()
at Volo.Abp.Uow.UnitOfWorkInterceptor.InterceptAsync(IAbpMethodInvocation invocation)
at Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter`1.InterceptAsync(IInvocation invocation, IInvocationProceedInfo proceedInfo, Func`3 proceed)
at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.TaskResultExecutor.Execute(ActionContext actionContext, IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeActionMethodAsync>g__Logged|12_1(ControllerActionInvoker invoker)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeNextActionFilterAsync>g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeInnerFilterAsync>g__Awaited|13_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextExceptionFilterAsync>g__Awaited|26_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
2024-05-03 13:49:07.572 +00:00 [WRN] (Instance: 53d7) Code:Volo.Abp.Identity:PasswordRequiresNonAlphanumeric
2024-05-03 13:49:07.572 +00:00 [WRN] (Instance: 53d7) Details:
2024-05-03 13:49:07.575 +00:00 [INF] (Instance: 53d7) Executing ObjectResult, writing value of type 'Volo.Abp.Http.RemoteServiceErrorResponse'.
2024-05-03 13:49:07.578 +00:00 [INF] (Instance: 53d7) Executed action Volo.Abp.Account.ProfileController.ChangePasswordAsync (Volo.Abp.Account.Pro.Public.HttpApi) in 242.5297ms
2024-05-03 13:49:07.578 +00:00 [INF] (Instance: 53d7) Executed endpoint 'Volo.Abp.Account.ProfileController.ChangePasswordAsync (Volo.Abp.Account.Pro.Public.HttpApi)'
2024-05-03 13:49:07.626 +00:00 [INF] (Instance: 53d7) Request finished HTTP/1.1 POST https://eiufsd.nvisiononline.net/api/account/my-profile/change-password application/json 99 - 403 - application/json;+charset=utf-8 325.1399ms
ABP Commercial 7.4.2 / Blazor Server / EF / Non tiered / Separate Host and Tenant DBs / Lepton Theme:
Hi,
We have a client in production that is getting the following ABP error when attempting to change their password.
We cannot replicate the issue in our QA environment.
Please advise and let us know of any troubleshooting steps we can take.
Thank you.
Thanks for confirming IanW.
We came up with an approach similar to what you described.
ABP Commercial 7.4.2 / Blazor Server / EF / Non tiered / Separate Host and Tenant DBs / Lepton Theme
Hi,
Our entire user base will always be located in the same time zone which is different than UTC and we would like the end user to always see their local time (East US).
We've read https://docs.abp.io/en/abp/latest/Timing and still are unsure of how to handle the following scenario...
In local development, we can convert ABP stored UTC values as pages load and everything works correctly, however this approach doesn't work when we deploy to Azure.
This is because the environments running in Azure have a local time of UTC. So we can't use CreationDateTime.ToLocalTime()
as it will always return a UTC time instead of East US.
Is there anyway around this or a certain recommended approach?
Thanks in advance.
Excellent, this was very helpful. Thanks @maliming!
ABP Commercial 7.4.2 / Blazor Server / EF / Non tiered / Separate Host and Tenant DBs / Lepton Theme
Hi, We have successfully overridden the Change Password UI (see solution structure below). The problem is that we need to reference a new javascript file in the overridden page to augment it's functionality.
In Pages/Account/Components/ProfileManagementGroup/Password/Default.cshtml, we attempted to add the following and at runtime but the page never includes the javascript reference.
This didn't work:
@section scripts
{
<script type="text/javascript" src="/Pages/Account/PasswordStrength.js"></script>
}
and this didn't work
@section scripts
{
<abp-script-bundle name="@typeof(ManageModel).FullName">
<abp-script src="/Pages/Account/PasswordStrength.js" />
</abp-script-bundle>
}
Is there something different that needs to be done with these view components (password, personalinfo, profilepicture, etc)?
Hi you can access a video using the link below...
The video shows the following...
https://www.icloud.com/iclouddrive/08aBbYcniD17PdTME67mBM9RQ#Demo_CSD_-_Google_Chrome_2023-12-14_23-26-58
Item 2 is the scenario where we want to redirect to a custom access denied page.