private static UserInfo GetOrCreateCachedUserInfo(JwtSecurityToken jwt, PortalSettings portalSettings, System.Security.Claims.Claim userClaim) { var usernamePrefixEnabled = bool.Parse(AzureConfig.GetSetting(AzureConfig.ServiceName, "UsernamePrefixEnabled", portalSettings.PortalId, "true")); var usernameToFind = usernamePrefixEnabled ? $"azure-{userClaim.Value}" : userClaim.Value; var userInfo = UserController.GetUserByName(portalSettings.PortalId, usernameToFind); var tokenKey = ComputeSha256Hash(jwt.RawData); var cache = DotNetNuke.Services.Cache.CachingProvider.Instance(); if (string.IsNullOrEmpty((string)cache.GetItem($"SyncAADToken|{tokenKey}"))) { var azureClient = new AzureClient(portalSettings.PortalId, AuthMode.Login) { JwtIdToken = jwt }; azureClient.SetAuthTokenInternal(jwt.RawData); azureClient.SetAutoMatchExistingUsers(true); var userData = azureClient.GetCurrentUserInternal(jwt); if (userInfo == null) { // If user doesn't exist, create the user userInfo = userData.ToUserInfo(usernamePrefixEnabled); userInfo.PortalID = portalSettings.PortalId; userInfo.Membership.Password = UserController.GeneratePassword(); var result = UserController.CreateUser(ref userInfo); } azureClient.AuthenticateUser(userData, portalSettings, HttpContext.Current.Request["REMOTE_ADDR"], azureClient.AddCustomProperties, azureClient.OnUserAuthenticated); azureClient.UpdateUserProfile(jwt, false, false); cache.Insert($"SyncAADToken|{tokenKey}", "OK", null, jwt.ValidTo, TimeSpan.Zero); } return(userInfo); }
public override void AuthenticateUser(UserData user, PortalSettings settings, string IPAddress, Action <NameValueCollection> addCustomProperties, Action <UserAuthenticatedEventArgs> onAuthenticated) { var portalSettings = settings; if (IsCurrentUserAuthorized() && JwtIdToken != null) { // Check if portalId profile mapping exists var portalUserMapping = UserMappingsRepository.Instance.GetUserMapping("PortalId", GetCalculatedPortalId()); if (!string.IsNullOrEmpty(portalUserMapping?.AadClaimName)) { var claimName = portalUserMapping?.AadClaimName; // Get PortalId from claim var portalIdClaim = JwtIdToken.Claims.FirstOrDefault(x => x.Type == claimName)?.Value; if (string.IsNullOrEmpty(portalIdClaim)) { throw new SecurityTokenException("The user has no portalId claim and portalId profile mapping is setup. The AAD user can't login to any portal until the portalId attribute has been setup for the user. Ensure that the PortalId claim has been setup and included on the policy being used."); } if (int.TryParse(portalIdClaim, out int portalId) && portalId != portalSettings.PortalId) { // Redirect to the user portal var request = HttpContext.Current.Request; if (!string.IsNullOrEmpty(request.Headers["Authorization"]) && request.Headers["Authorization"].StartsWith("Bearer")) { throw new SecurityTokenException($"The user portalId claim ({portalId}) is different from current portalId ({portalSettings.PortalId}). Portal redirection flow is not supported on native apps. Please call the API from the corresponding portal URL"); } var state = new State(request["state"]); HttpContext.Current.Response.Redirect(Utils.GetLoginUrl(portalId, state.Culture, request)); return; } } } var userIdClaim = Utils.GetUserIdClaim(GetCalculatedPortalId()); var userClaim = JwtIdToken.Claims.FirstOrDefault(x => x.Type == userIdClaim); if (userClaim == null) { if (Logger.IsDebugEnabled) { Logger.Error($"Can't find '{userIdClaim}' claim on token"); } throw new MissingFieldException($"Can't find '{userIdClaim}' claim on token, needed to identify the user"); } var usernamePrefixEnabled = bool.Parse(AzureConfig.GetSetting(AzureConfig.ServiceName, "UsernamePrefixEnabled", portalSettings.PortalId, "true")); var usernameToFind = usernamePrefixEnabled ? $"azure-{userClaim.Value}" : userClaim.Value; var userInfo = UserController.GetUserByName(portalSettings.PortalId, usernameToFind); // If user doesn't exist on current portal, AuthenticateUser() will create it. // Otherwise, AuthenticateUser will perform a Response.Redirect, so we have to sinchronize the roles before that, to avoid the ThreadAbortException caused by the Response.Redirect if (userInfo == null) { base.AuthenticateUser(user, portalSettings, IPAddress, addCustomProperties, onAuthenticated); if (IsCurrentUserAuthorized()) { userInfo = UserController.GetUserByName(portalSettings.PortalId, usernameToFind); if (userInfo == null) { throw new SecurityTokenException($"The logged in user {usernameToFind} does not belong to PortalId {portalSettings.PortalId}"); } UpdateUserAndRoles(userInfo); MarkUserAsAad(userInfo); } } else { if (IsCurrentUserAuthorized()) { UpdateUserAndRoles(userInfo); } base.AuthenticateUser(user, portalSettings, IPAddress, addCustomProperties, onAuthenticated); } }