public async Task <IActionResult> RegisterUser(RegisterUserViewModel model) { if (ModelState.IsValid) { // create user + claims var userToCreate = new Galal.IDP.Entities.User(); userToCreate.SubjectId = Guid.NewGuid().ToString(); userToCreate.Password = model.Password; userToCreate.Username = model.Username; userToCreate.IsActive = true; userToCreate.Claims.Add(new Galal.IDP.Entities.UserClaim("country", model.Country)); userToCreate.Claims.Add(new Galal.IDP.Entities.UserClaim("address", model.Address)); userToCreate.Claims.Add(new Galal.IDP.Entities.UserClaim("given_name", model.Firstname)); userToCreate.Claims.Add(new Galal.IDP.Entities.UserClaim("family_name", model.Lastname)); userToCreate.Claims.Add(new Galal.IDP.Entities.UserClaim("email", model.Email)); userToCreate.Claims.Add(new Galal.IDP.Entities.UserClaim("subscriptionlevel", "FreeUser")); // if we're provisioning a user via external login, we must add the provider & // user id at the provider to this user's logins if (model.IsProvisioningFromExternal) { userToCreate.Logins.Add(new Galal.IDP.Entities.UserLogin() { LoginProvider = model.Provider, ProviderKey = model.ProviderUserId }); } // add it through the repository _IDPUserRepository.AddUser(userToCreate); if (!_IDPUserRepository.Save()) { throw new Exception($"Creating a user failed."); } if (!model.IsProvisioningFromExternal) { // log the user in await HttpContext.SignInAsync(userToCreate.SubjectId, userToCreate.Username); } // continue with the flow if (_interaction.IsValidReturnUrl(model.ReturnUrl) || Url.IsLocalUrl(model.ReturnUrl)) { return(Redirect(model.ReturnUrl)); } return(Redirect("~/")); } // ModelState invalid, return the view with the passed-in model // so changes can be made return(View(model)); }
public async Task <IActionResult> Callback() { // read external identity from the temporary cookie var result = await HttpContext.AuthenticateAsync(IdentityServer4.IdentityServerConstants.ExternalCookieAuthenticationScheme); // retrieve return URL var returnUrl = result.Properties.Items["returnUrl"] ?? "~/"; if (result?.Succeeded != true) { throw new Exception("External authentication error"); } if (_logger.IsEnabled(LogLevel.Debug)) { var externalClaims = result.Principal.Claims.Select(c => $"{c.Type}: {c.Value}"); _logger.LogDebug("External claims: {@claims}", externalClaims); } // lookup our user and external provider info var(user, provider, providerUserId, claims) = FindUserFromExternalProvider(result); //if (user == null) //{ // // this might be where you might initiate a custom workflow for user registration // // in this sample we don't show how that would be done, as our sample implementation // // simply auto-provisions new external user // user = AutoProvisionUser(provider, providerUserId, claims); //} if (user == null) { // user wasn't found by provider, but maybe one exists with the same email address? if (provider == "Facebook") { // email claim from Facebook var email = claims.FirstOrDefault(c => c.Type == "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress"); if (email != null) { var userByEmail = _IDPUserRepository.GetUserByEmail(email.Value); if (userByEmail != null) { // add Facebook as a provider for this user _IDPUserRepository.AddUserLogin(userByEmail.SubjectId, provider, result.Principal.Claims.FirstOrDefault(x => x.Type == JwtClaimTypes.Subject).Value); if (!_IDPUserRepository.Save()) { throw new Exception($"Adding a login for a user failed."); } // redirect to ExternalLoginCallback var continueWithUrlAfterAddingUserLogin = Url.Action("ExternalLoginCallback", new { returnUrl = returnUrl }); return(Redirect(continueWithUrlAfterAddingUserLogin)); } } } // retrieve return URL // var returnUrl = result.Properties.Items["returnUrl"] ?? "~/"; user = AutoProvisionUser(provider, providerUserId, claims); var returnUrlAfterRegisteration = Url.Action("Callback", new { returnUrl = returnUrl }); var continueWithUrl = Url.Action("RegisterUser", "UserRegisteration" , new { returnUrl = returnUrlAfterRegisteration, provider = provider, providerUserId = result.Principal.Claims.FirstOrDefault(x => x.Type == JwtClaimTypes.Subject).Value }); return(Redirect(continueWithUrl)); } // this allows us to collect any additonal claims or properties // for the specific prtotocols used and store them in the local auth cookie. // this is typically used to store data needed for signout from those protocols. var additionalLocalClaims = new List <Claim>(); var localSignInProps = new AuthenticationProperties(); ProcessLoginCallbackForOidc(result, additionalLocalClaims, localSignInProps); ProcessLoginCallbackForWsFed(result, additionalLocalClaims, localSignInProps); ProcessLoginCallbackForSaml2p(result, additionalLocalClaims, localSignInProps); // issue authentication cookie for user await HttpContext.SignInAsync(user.SubjectId, user.Username, provider, localSignInProps, additionalLocalClaims.ToArray()); // delete temporary cookie used during external authentication await HttpContext.SignOutAsync(IdentityServer4.IdentityServerConstants.ExternalCookieAuthenticationScheme); // check if external login is in the context of an OIDC request var context = await _interaction.GetAuthorizationContextAsync(returnUrl); await _events.RaiseAsync(new UserLoginSuccessEvent(provider, providerUserId, user.SubjectId, user.Username, true, context?.ClientId)); if (context != null) { if (await _clientStore.IsPkceClientAsync(context.ClientId)) { // if the client is PKCE then we assume it's native, so this change in how to // return the response is for better UX for the end user. return(View("Redirect", new RedirectViewModel { RedirectUrl = returnUrl })); } } return(Redirect(returnUrl)); }