ASP.NET 6.0 solution that showcases an identity provider, an Angular client, and a separate API working together with authentication and authorization in a multi-tenant system
Implement end-session endpoint behavior to properly handle client logout requests
Figure out how to approach local signout on IDP or scrap it
For now, if local signout isn't really the proper approach, immediately just remove the functionality as the local code may need to be removed eventually. However local signout may be easy even if it isn't really a common approach.
Scenario:
User has a tab 1 open and is logged in, accessing the website
User opens a copy of tab 1 (tab 2), then logs out and into a separate account
User closes tab 2 and returns to tab 1
Currently the application locks up, ideally it should update and continue on normally with the new user subject & token. Likely an issue in how I am handling the getUser() Observable in the tenant manager service.
Investigate prior to implementation. What is the general approach, store their profile information locally? Use only via jwt? Either remove current external identity provider code or add full support.
Registration will be enabled initially via 1 method.
Via invite link
Quick and easy way to invite others without necessarily exposing the id of the Organization.
To have all of this work
IUserOrganizationRepository - Handles join table db operations
void CreateAsync(Guid userId, Guid orgId)
void DeleteAsync(Guid userId, Guid orgId)
bool ExistsAsync(Guid userId, Guid orgId)
IOrganizationAccessManager - Handles modification of privileges
AccessModifiedResult GrantAccessAsync(User user, Organization org)
Null check. Use a try/catch block and call the repo's CreateAsync method. If anything fails, return false.
bool RevokeAccessAsync(User user, Organization org)
Validate same as above. Then use a try/catch block and call the repo's DeleteAsync method. Return false if anything fails.
bool UserHasAccessAsync(User user, Organization org)
Don't over-validate the User and Organization. Just do a quick check to see if there is a record with the given id values.
IOrganizationInviteService
string CreatePermanentInvitationLink(Organization org)
Use private methods to generate link value.
InviteResult UsePermanentInvitationLink(Guid userId, string link)
Validate active User in this session. Attempt to decode the link and then verify there is a corresponding Organization with the decoded value. Ensure Organization is active. Attempt to grant access and check if the organization requires confirmation.
Private CreatePermanentCode/DecodePermanentCode, already made
Results and final controller flow
Add AccessModifiedResult - Success, whether it requires confirmation, user has existing access, etc.
Create logged in partial view to be used across the site
Create style and logic using SignInManager and call the partial view from other views
Create Settings page
Account settings pages
Page with tabs and panel
Make a layout file that is essentially the normal layout file with tabs and a panel. Have a data-isActive or similar attribute for tabs that is set via conditional checks of some ViewData["ActiveTab"] or similar dictionary data. The main RenderBody call just shows the panel output.
Forms and controller actions for account changes
Because the complex forms will be client-implemented we can probably just do some non-ajax vanilla forms. KISS
Update RedirectToAction calls etc. in other pagemodels
Figure out issue with TempData lagging behind (had this issue previously, too)
Play around with css/html, see if we cannot just style the text and put the ul inside existing custom validation message
Ensure that if the page has an error, we just use that now. In other words, the only usage left for custom validation viewdata partial would be if you want a successful return message without a redirect. Update documentation and pagemodel code to reflect this.
Rolling out in multiple phases
Phase 1 - Remote Authorization
Phase 2 - User-defined roles based on available permissions
Phase 3 - UI for defining these roles
GET Login
Check and ensure that a user with an existing token is handled properly.
Make sure returnUrl queryparam is persisted
POST Login
Do expected operations, persists returnUrl queryparam.
On successful login, either redirect back if SelectedOrg is set or redirect to Portal with redirectUrl query.
Change login page code to redirect back to client and handle associated cases/errors
Update mvc application code to act as a client here, don't worry about the local Idp pages as much. Focus on the end behavior as an identity provider that redirects and handles authentication
Find a place to put AccountOptions (probably with Config, SecurityHeadersAttribute)
Add AccessDenied page (cancelled)
Add LoadingPage functionality via extension method