/// <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 обрабатывает запрос на {context.Request.Uri}"); ClaimsIdentity identity = null; using (var db = new ULearnDb()) { var loginProvider = string.Join(":", context.Options.AuthenticationType, context.LtiRequest.ConsumerKey); var providerKey = context.LtiRequest.UserId; var ltiLogin = new UserLoginInfo(loginProvider, providerKey); identity = await FuncUtils.TrySeveralTimesAsync( // ReSharper disable once AccessToDisposedClosure () => GetIdentityForLtiLogin(context, db, ltiLogin), 3, () => Task.Delay(200) ); } if (identity == null) { throw new Exception("Can\'t authenticate identity for LTI user"); } log.Info($"Аутенфицирую пользователя по identity: {identity.Name}"); context.OwinContext.Authentication.SignIn(new AuthenticationProperties { IsPersistent = false }, identity); }
/// <summary> /// Handles LTI authentication requests. /// </summary> /// <returns>True if the request was handled, false if the next middleware in the pipeline /// should be invoked.</returns> public override async Task <bool> InvokeAsync() { if (await Request.IsAuthenticatedLtiRequestAsync()) { var ltiRequest = await Request.ParseLtiRequestAsync(); // Let the application validate the parameters var authenticateContext = new LtiAuthenticateContext(Context, ltiRequest); await Options.Provider.Authenticate(authenticateContext); // Let the application sign in the application user if required var authenticatedContext = new LtiAuthenticatedContext(Context, Options, ltiRequest); await Options.Provider.Authenticated(authenticatedContext); if (!string.IsNullOrEmpty(authenticatedContext.RedirectUrl)) { // Stop processing the current request and redirect to the new URL Response.Redirect(authenticatedContext.RedirectUrl); return(true); } } // Continue processing the request return(false); }
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(); }
public virtual Task Authenticated(LtiAuthenticatedContext context) { return OnAuthenticated.Invoke(context); }
/// <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(); }