private static async Task <ClaimsIdentity> GetIdentityForLtiLogin(LtiAuthenticatedContext context, ULearnDb db, UserLoginInfo ltiLogin) { var userManager = new ULearnUserManager(db); using (var transaction = db.Database.BeginTransaction(IsolationLevel.Serializable)) { var ltiLoginUser = await userManager.FindAsync(ltiLogin); if (ltiLoginUser != null) { log.Info($"Нашёл LTI-логин: провайдер {ltiLogin.LoginProvider}, идентификатор {ltiLogin.ProviderKey}, он принадлежит пользователю {ltiLoginUser.UserName} (Id = {ltiLoginUser.Id})"); return(await userManager.CreateIdentityAsync(ltiLoginUser, context.Options.SignInAsAuthenticationType)); } log.Info($"Не нашёл LTI-логин: провайдер {ltiLogin.LoginProvider}, идентификатор {ltiLogin.ProviderKey}"); if (IsAuthenticated(context.OwinContext)) { var ulearnPrincipal = context.OwinContext.Authentication.User; log.Info($"Пришёл LTI-запрос на аутенфикацию, пользователь уже аутенфицирован на ulearn: {ulearnPrincipal.Identity.Name}. Прикрепляю к пользователю LTI-логин"); await userManager.AddLoginAsync(ulearnPrincipal.Identity.GetUserId(), ltiLogin); return((ClaimsIdentity)ulearnPrincipal.Identity); } var usernameContext = new LtiGenerateUserNameContext(context.OwinContext, context.LtiRequest); await context.Options.Provider.GenerateUserName(usernameContext); if (string.IsNullOrEmpty(usernameContext.UserName)) { throw new Exception("Can't generate username"); } log.Info($"Сгенерировал имя пользователя для LTI-пользователя: {usernameContext.UserName}, ищу пользователя по этому имени"); var ulearnUser = await userManager.FindByNameAsync(usernameContext.UserName); if (ulearnUser == null) { log.Info("Не нашёл пользователя с таким именем, создаю нового"); ulearnUser = new ApplicationUser { UserName = usernameContext.UserName }; var result = await userManager.CreateAsync(ulearnUser); if (!result.Succeeded) { var errors = string.Join("\n\n", result.Errors); throw new Exception("Can't create user for LTI: " + errors); } } await userManager.AddLoginAsync(ulearnUser.Id, ltiLogin); var identity = await userManager.CreateIdentityAsync(ulearnUser, context.Options.SignInAsAuthenticationType); transaction.Commit(); return(identity); } }
/// <summary> /// Invoked after the LTI request has been authenticated so the application can sign in the application user. /// </summary> /// <param name="context">Contains information about the login session as well as the LTI request.</param> /// <param name="claims">Optional set of claims to add to the identity.</param> /// <returns>A <see cref="Task"/> representing the completed operation.</returns> public static async Task OnAuthenticated <TManager, TUser>(LtiAuthenticatedContext context, IEnumerable <Claim> claims = null) where TManager : UserManager <TUser, string> where TUser : IdentityUser, new() { // Find existing pairing between LTI user and application user var userManager = context.OwinContext.GetUserManager <TManager>(); var loginProvider = string.Join(":", new [] { context.Options.AuthenticationType, context.LtiRequest.ConsumerKey }); var providerKey = context.LtiRequest.UserId; var login = new UserLoginInfo(loginProvider, providerKey); var user = await userManager.FindAsync(login); if (user == null) { var usernameContext = new LtiGenerateUserNameContext(context.OwinContext, context.LtiRequest); await context.Options.Provider.GenerateUserName(usernameContext); if (string.IsNullOrEmpty(usernameContext.UserName)) { return; } user = await userManager.FindByNameAsync(usernameContext.UserName); if (user == null) { user = new TUser { UserName = usernameContext.UserName, Email = usernameContext.UserName }; var result = await userManager.CreateAsync(user); if (!result.Succeeded) { return; } } // Save the pairing between LTI user and application user await userManager.AddLoginAsync(user.Id, login); } // Create the application identity, add the LTI request as a claim, and sign in var identity = await userManager.CreateIdentityAsync(user, context.Options.SignInAsAuthenticationType); identity.AddClaim(new Claim(context.Options.ClaimType, JsonConvert.SerializeObject(context.LtiRequest, Formatting.None, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }), ClaimValueTypes.String, context.Options.AuthenticationType)); if (claims != null) { foreach (var claim in claims) { identity.AddClaim(claim); } } context.OwinContext.Authentication.SignIn(new AuthenticationProperties { IsPersistent = false }, identity); // Redirect to original URL so the new identity takes affect context.RedirectUrl = context.LtiRequest.Url.ToString(); }
/// <summary> /// Invoked after the LTI request has been authenticated so the application can sign in the application user. /// </summary> /// <param name="context">Contains information about the login session as well as the LTI request.</param> /// <param name="claims">Optional set of claims to add to the identity.</param> /// <returns>A <see cref="Task"/> representing the completed operation.</returns> public static async Task OnAuthenticated(LtiAuthenticatedContext context, IEnumerable<Claim> claims = null) { // Find existing pairing between LTI user and application user var userManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new LtiDb())); var loginProvider = string.Join(":", new[] { context.Options.AuthenticationType, context.LtiRequest.ConsumerKey }); var providerKey = context.LtiRequest.UserId; var login = new UserLoginInfo(loginProvider, providerKey); var user = await userManager.FindAsync(login); if (user == null) { var usernameContext = new LtiGenerateUserNameContext(context.OwinContext, context.LtiRequest); await context.Options.Provider.GenerateUserName(usernameContext); if (string.IsNullOrEmpty(usernameContext.UserName)) { return; } user = await userManager.FindByNameAsync(usernameContext.UserName); if (user == null) { user = new ApplicationUser { UserName = usernameContext.UserName }; var result = await userManager.CreateAsync(user); if (!result.Succeeded) { return; } } // Save the pairing between LTI user and application user await userManager.AddLoginAsync(user.Id, login); } // Create the application identity, add the LTI request as a claim, and sign in var identity = await userManager.CreateIdentityAsync(user, context.Options.SignInAsAuthenticationType); identity.AddClaim(new Claim(context.Options.ClaimType, JsonConvert.SerializeObject(context.LtiRequest, Formatting.None, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }), ClaimValueTypes.String, context.Options.AuthenticationType)); if (claims != null) { foreach (var claim in claims) { identity.AddClaim(claim); } } context.OwinContext.Authentication.SignIn(new AuthenticationProperties { IsPersistent = false }, identity); // Redirect to original URL so the new identity takes affect context.RedirectUrl = context.LtiRequest.Url.ToString(); }
/// <summary> /// Generate a valid application username using information from an LTI request. The default /// ASP.NET application using Microsoft Identity uses an email address as the username. This /// code will generate an "anonymous" email address if one is not supplied in the LTI request. /// </summary> /// <param name="context">Contains information about the login session as well as the LTI request.</param> /// <returns>A <see cref="Task"/> representing the completed operation.</returns> public static Task OnGenerateUserName(LtiGenerateUserNameContext context) { if (string.IsNullOrEmpty(context.LtiRequest.LisPersonEmailPrimary)) { var username = context.LtiRequest.UserId; Uri url; if (string.IsNullOrEmpty(context.LtiRequest.ToolConsumerInstanceUrl) || !Uri.TryCreate(context.LtiRequest.ToolConsumerInstanceUrl, UriKind.Absolute, out url)) { context.UserName = string.Concat(username, "@", context.LtiRequest.ConsumerKey); } else { context.UserName = string.Concat(username, "@", url.Host); } } else { context.UserName = context.LtiRequest.LisPersonEmailPrimary; } return(Task.FromResult <object>(null)); }
/// <summary> /// Generate a valid application username using information from an LTI request. The default /// ASP.NET application using Microsoft Identity uses an email address as the username. This /// code will generate an "anonymous" email address if one is not supplied in the LTI request. /// </summary> /// <param name="context">Contains information about the login session as well as the LTI request.</param> /// <returns>A <see cref="Task"/> representing the completed operation.</returns> public static Task OnGenerateUserName(LtiGenerateUserNameContext context) { if (string.IsNullOrEmpty(context.LtiRequest.LisPersonEmailPrimary)) { var username = string.Concat("anon_", context.LtiRequest.UserId); Uri url; if (string.IsNullOrEmpty(context.LtiRequest.ToolConsumerInstanceUrl) || !Uri.TryCreate(context.LtiRequest.ToolConsumerInstanceUrl, UriKind.Absolute, out url)) { context.UserName = string.Concat(username, "@anon_", context.LtiRequest.ConsumerKey, ".lti"); } else { context.UserName = string.Concat(username, "@", url.Host); } } else { context.UserName = context.LtiRequest.LisPersonEmailPrimary; } return Task.FromResult<object>(null); }
/// <summary> /// Invoked after the LTI request has been authenticated so the application can sign in the application user. /// </summary> /// <param name="context">Contains information about the login session as well as the LTI request.</param> /// <param name="claims">Optional set of claims to add to the identity.</param> /// <returns>A <see cref="Task"/> representing the completed operation.</returns> public static async Task OnAuthenticated(LtiAuthenticatedContext context, IEnumerable <Claim> claims = null) { ClaimsIdentity identity; if (!IsAuthenticated(context.OwinContext)) { // Find existing pairing between LTI user and application user var userManager = new UserManager <ApplicationUser>(new UserStore <ApplicationUser>(new ULearnDb())); var loginProvider = string.Join(":", new[] { context.Options.AuthenticationType, context.LtiRequest.ConsumerKey }); var providerKey = context.LtiRequest.UserId; var login = new UserLoginInfo(loginProvider, providerKey); var user = await userManager.FindAsync(login); if (user == null) { var usernameContext = new LtiGenerateUserNameContext(context.OwinContext, context.LtiRequest); await context.Options.Provider.GenerateUserName(usernameContext); if (string.IsNullOrEmpty(usernameContext.UserName)) { throw new Exception("Can't generate username"); } user = await userManager.FindByNameAsync(usernameContext.UserName); if (user == null) { user = new ApplicationUser { UserName = usernameContext.UserName }; var result = await userManager.CreateAsync(user); if (!result.Succeeded) { var errors = String.Join("\n\n", result.Errors); throw new Exception("Can't create user: "******"LtiRequest")); foreach (var claim in claimsToRemove) { identity.RemoveClaim(claim); } identity.AddClaim(new Claim(context.Options.ClaimType, json, ClaimValueTypes.String, context.Options.AuthenticationType)); if (claims != null) { foreach (var claim in claims) { identity.AddClaim(claim); } } context.OwinContext.Authentication.SignIn(new AuthenticationProperties { IsPersistent = false }, identity); // Redirect to original URL so the new identity takes affect context.RedirectUrl = context.LtiRequest.Url.ToString(); }
/// <summary> /// Invoked after the LTI request has been authenticated so the application can sign in the application user. /// </summary> /// <param name="context">Contains information about the login session as well as the LTI request.</param> /// <param name="claims">Optional set of claims to add to the identity.</param> /// <returns>A <see cref="Task"/> representing the completed operation.</returns> public static async Task OnAuthenticated(LtiAuthenticatedContext context, IEnumerable<Claim> claims = null) { log.Info($"LTI вызвал событие OnAuthenticated при запросе на {context.Request.Uri}"); ClaimsIdentity identity; if (!IsAuthenticated(context.OwinContext)) { // Find existing pairing between LTI user and application user var userManager = new ULearnUserManager(); var loginProvider = string.Join(":", context.Options.AuthenticationType, context.LtiRequest.ConsumerKey); var providerKey = context.LtiRequest.UserId; var login = new UserLoginInfo(loginProvider, providerKey); var user = await userManager.FindAsync(login); log.Info($"Ищу пользователя: провайдер {loginProvider}, идентификатор {providerKey}"); if (user == null) { log.Info("Не нашёл пользователя"); var usernameContext = new LtiGenerateUserNameContext(context.OwinContext, context.LtiRequest); log.Info("Генерирую имя пользователя для LTI-пользователя"); await context.Options.Provider.GenerateUserName(usernameContext); if (string.IsNullOrEmpty(usernameContext.UserName)) { throw new Exception("Can't generate username"); } log.Info($"Сгенерировал: {usernameContext.UserName}, ищу пользователя по этому имени"); user = await userManager.FindByNameAsync(usernameContext.UserName); if (user == null) { log.Info("Не нашёл пользователя с таким именем, создаю нового"); user = new ApplicationUser { UserName = usernameContext.UserName }; var result = await userManager.CreateAsync(user); if (!result.Succeeded) { var errors = string.Join("\n\n", result.Errors); throw new Exception("Can't create user: "******"Добавляю LTI-логин {login} к пользователю {user.VisibleName} (Id = {user.Id})"); // Save the pairing between LTI user and application user await userManager.AddLoginAsync(user.Id, login); } log.Info($"Подготавливаю identity для пользователя {user.VisibleName} (Id = {user.Id})"); // Create the application identity, add the LTI request as a claim, and sign in identity = await userManager.CreateIdentityAsync(user, context.Options.SignInAsAuthenticationType); } else { log.Info($"Пришёл LTI-запрос на аутенфикацию, но пользователь уже аутенфицирован на ulearn: {context.OwinContext.Authentication.User.Identity.Name}"); identity = (ClaimsIdentity)context.OwinContext.Authentication.User.Identity; } var json = JsonConvert.SerializeObject(context.LtiRequest, Formatting.None, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }); log.Info($"LTI-запрос: {json}"); var claimsToRemove = identity.Claims.Where(c => c.Type.Equals("LtiRequest")); foreach (var claim in claimsToRemove) { log.Info($"Требование в LTI-запросе: {claim}"); identity.RemoveClaim(claim); } identity.AddClaim(new Claim(context.Options.ClaimType, json, ClaimValueTypes.String, context.Options.AuthenticationType)); if (claims != null) { foreach (var claim in claims) { identity.AddClaim(claim); } } log.Info($"Аутенфицирую identity: {identity.Name}"); context.OwinContext.Authentication.SignIn(new AuthenticationProperties { IsPersistent = false }, identity); // Redirect to original URL so the new identity takes affect context.RedirectUrl = context.LtiRequest.Url.ToString(); }
public virtual Task GenerateUserName(LtiGenerateUserNameContext context) { return OnGenerateUserName.Invoke(context); }