Пример #1
0
        /// <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);
        }
Пример #3
0
        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);
            }
        }
Пример #4
0
        /// <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();
        }
Пример #5
0
		/// <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);
 }
Пример #7
0
        /// <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();
        }
Пример #8
0
		/// <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();
		}