예제 #1
0
        public User SignupUser([FromBody] UserSignup signup)
        {
            // signup request contains password, so mark it confidential, so the request body will NOT be logged
            //  to prevent passwords appearing in logs
            this.WebContext.Flags |= WebCallFlags.Confidential;

            //Validate
            OpContext.ThrowIfNull(signup, ClientFaultCodes.InvalidValue, "UserSignup", "UserSignup object may not be null.");
            OpContext.ValidateNotEmpty(signup.UserName, "UserName", "UserName may not be empty.");
            OpContext.ValidateNotEmpty(signup.Password, "Password", "Password may not be empty.");
            OpContext.ThrowValidation();
            var session = OpenSession();
            // check if user name is already taken
            var existingUser = session.EntitySet <IUser>().Where(u => u.UserName == signup.UserName).WithOptions(QueryOptions.ForceIgnoreCase).FirstOrDefault();

            OpContext.ThrowIf(existingUser != null, ClientFaultCodes.InvalidValue, "UserName", "User name {0} is already in use. Please choose other name.", signup.UserName);
            // create login and user
            var loginMgr = OpContext.App.GetService <ILoginManagementService>();
            var user     = session.NewUser(signup.UserName, UserType.Customer, signup.UserName);
            var login    = loginMgr.NewLogin(session, signup.UserName, signup.Password, loginId: user.Id, userId: user.Id); //Login.Id is the same as userID

            session.SaveChanges();
            // Let's create custom app event; we test here that this appEvent gets to AppEventLog
            //  log entries in web app are accumulated in buffered log attached to web call, and later
            // dumped to WebCallLog.OperationLog column as text. Except - errors and app events, they are
            // passed to global log as well.
            OpContext.WriteAppEvent("Customer", "Signup", $"Customer {signup.UserName} signed up.");
            return(user.ToModel());
        }
예제 #2
0
        public BookOrder UpdateOrder(BookOrder order)
        {
            var session = OpenSession();
            var cart    = GetOpenOrder(session, LockType.ForUpdate, create: true);

            foreach (var item in order.Items)
            {
                OpContext.ThrowIf(item.Quantity < 0, ClientFaultCodes.InvalidValue, "Quantity", "Quantity may not be negative.");
                OpContext.ThrowIf(item.Quantity > 10, ClientFaultCodes.InvalidValue, "Quantity", "Quantity may not be more than 10.");
                var orderLine = cart.Lines.FirstOrDefault(ln => ln.Book.Id == item.Book.Id);
                if (orderLine == null)
                {
                    if (item.Quantity > 0)
                    {
                        var bk = session.GetEntity <IBook>(item.Book.Id);
                        OpContext.ThrowIfNull(bk, ClientFaultCodes.ObjectNotFound, "Book", "Book not found.");
                        cart.Add(bk, item.Quantity);
                        continue;
                    }
                }
                else //orderLine != null
                if (item.Quantity == 0)
                {
                    session.DeleteEntity(orderLine);
                }
                else
                {
                    orderLine.Quantity = item.Quantity;
                }
            }
            cart.ScheduleUpdateTotal();
            session.SaveChanges();
            EntityHelper.RefreshEntity(cart); //to make sure total from database is refreshed in entity
            return(cart.ToModel(details: true));
        }
예제 #3
0
        public async Task SendPin([FromBody] SendPinRequest request)
        {
            OpContext.WebContext.MarkConfidential();
            OpContext.ThrowIfNull(request, ClientFaultCodes.ContentMissing, "SendPinRequest", "Pin request object must be provided.");
            OpContext.ValidateNotEmpty(request.ProcessToken, "ProcessToken", "Process token should be provided.");
            OpContext.ValidateNotEmpty(request.Factor, "Factor", "Factor (email or phone) should be provided.");
            OpContext.ThrowValidation();
            var session = OpContext.OpenSession();
            var process = GetActiveProcess(session, request.ProcessToken, confirmedOnly: false);

            if (process == null)
            {
                return; //no indication process exist or not
            }
            OpContext.ThrowIf(process.CurrentFactor != null, ClientFaultCodes.InvalidAction, "token", "The previous process step is not completed.");
            var iFactor = ProcessService.FindLoginExtraFactor(process.Login, request.Factor);

            //now having completed at least one extra factor, we can openly indicate that we could not find next factor
            OpContext.ThrowIfNull(iFactor, ClientFaultCodes.InvalidValue, "factor", "Login factor (email or phone) is not found for a user.");
            //Check that factor type is one in the pending steps
            var factorOk = process.PendingFactors.IsSet(iFactor.FactorType);

            OpContext.ThrowIf(!factorOk, ClientFaultCodes.InvalidValue, "factor", "Login factor type attempted (email or phone) is not pending in the process.");
            await ProcessService.SendPinAsync(process, iFactor, request.Factor); //we use factor from request, to avoid unencrypting twice
        }
예제 #4
0
        public LoginResponse CompleteMultiFactorLogin([FromBody] MultifactorLoginRequest request)
        {
            var session = OpContext.OpenSession();
            var process = GetMutiFactorProcess(session, request.ProcessToken);

            OpContext.ThrowIfNull(process, ClientFaultCodes.ObjectNotFound, "processToken", "Login process not found or expired.");
            OpContext.ThrowIf(process.PendingFactors != ExtraFactorTypes.None, ClientFaultCodes.InvalidValue, "PendingFactors",
                              "Multi-factor login process not completed, verification pending: {0}.", process.PendingFactors);
            var login = process.Login;

            var loginService = OpContext.App.GetService <ILoginService>();
            var loginResult  = loginService.CompleteMultiFactorLogin(OpContext, login);
            var displayName  = OpContext.App.GetUserDispalyName(OpContext.User);

            session.SaveChanges();
            return(new LoginResponse()
            {
                Status = LoginAttemptStatus.Success, SessionId = loginResult.SessionId,
                UserName = login.UserName, UserDisplayName = displayName,
                UserId = login.UserId, AltUserId = login.AltUserId, LoginId = login.Id,
                PasswordExpiresDays = login.GetExpiresDays(), Actions = loginResult.Actions,
                LastLoggedInOn = loginResult.PreviousLoginOn,
                AuthenticationToken = CreateAuthToken()
            });
        }//method
        public bool SubmitPin(Guid factorId, string pin)
        {
            OpContext.ThrowIfEmpty(pin, ClientFaultCodes.ValueMissing, "pin", "Pin value missing");
            var session = OpenSession();
            var login   = GetCurrentLogin(session);
            var factor  = login.ExtraFactors.FirstOrDefault(f => f.Id == factorId);

            OpContext.ThrowIfNull(factor, ClientFaultCodes.ObjectNotFound, "factor", "Factor not found, ID: {0}", factorId);
            var processService = OpContext.App.GetService <ILoginProcessService>();
            var processes      = processService.GetActiveConfirmationProcesses(factor, LoginProcessType.FactorVerification);

            OpContext.ThrowIf(processes.Count == 0, ClientFaultCodes.ObjectNotFound, "LoginProcess", "Confirmation process not found or expired.");
            try {
                foreach (var process in processes)
                {
                    if (processService.SubmitPin(process, pin))
                    {
                        return(true);
                    }
                }
                return(false);
            } finally {
                session.SaveChanges();
            }
        }
        public LoginInfo UpdateLoginInfo([FromBody] LoginInfo loginInfo)
        {
            var session = OpenSession();
            var login   = GetCurrentLogin(session);

            OpContext.ThrowIfNull(login, ClientFaultCodes.ContentMissing, "LoginInfo", "LoginInfo is missing.");
            OpContext.ThrowIf(loginInfo.Id != login.Id, ClientFaultCodes.InvalidValue, "Id", "Invalid login Id, must match current user's login id.");
            LoginManager.UpdateLogin(login, loginInfo);
            session.SaveChanges();
            return(login.ToModel());
        }
        public string GetGoogleAuthenticatorQrUrl(Guid id)
        {
            var session = OpenSession();
            var login   = GetCurrentLogin(session);
            var iFactor = session.GetEntity <ILoginExtraFactor>(id);

            OpContext.ThrowIfNull(iFactor, ClientFaultCodes.ObjectNotFound, "factor", "Factor not found, ID: {0}", id);
            //the following should be caught by Authorization
            OpContext.ThrowIf(iFactor.Login != login, ClientFaultCodes.InvalidAction, "id", "Factor does not belong to current user.");
            OpContext.ThrowIf(iFactor.FactorType != ExtraFactorTypes.GoogleAuthenticator, ClientFaultCodes.InvalidAction,
                              "FactorType", "Factor is not GoogleAuthenticator.");
            return(LoginManager.GetGoogleAuthenticatorQRUrl(iFactor));
        }
예제 #8
0
        public string Start([FromBody] PasswordResetStartRequest request)
        {
            var loginStt     = OpContext.App.GetConfig <LoginModuleSettings>();
            var obscured     = loginStt.Options.IsSet(LoginModuleOptions.ConcealMembership);
            var processToken = ProcessService.GenerateProcessToken();
            var session      = OpContext.OpenSession();
            var emailFactor  = ProcessService.FindLoginExtraFactor(session, ExtraFactorTypes.Email, request.Factor);

            if (emailFactor == null)
            {
                // If we need to conceal membership (we are a public p**n site), we have to pretend it went ok, and return processToken
                // so that we do not disclose if user's email is/is not in our database
                if (obscured)
                {
                    return(processToken);
                }
                else
                {
                    //if we are a specialized site and do not need to conceal membership (this might be annoying in a business system) -
                    // we return error
                    OpContext.ThrowIf(true, ClientFaultCodes.ObjectNotFound, "email", "Email {0} not found in database.", request.Factor);
                }
            }
            //check we can start login
            var login = emailFactor.Login;

            if (login.Flags.IsSet(LoginFlags.DoNotConcealMembership))
            {
                obscured = false;
            }

            bool accountBlocked = login.Flags.IsSet(LoginFlags.Disabled) || (login.Flags.IsSet(LoginFlags.Suspended) &&
                                                                             !loginStt.Options.IsSet(LoginModuleOptions.AllowPasswordResetOnSuspended));

            if (accountBlocked)
            {
                if (obscured)
                {
                    return(processToken);
                }
                else
                {
                    OpContext.ThrowIf(true, LoginFaultCodes.LoginDisabled, "Login", "Login is disabled.");
                }
            }
            //A flag in login entity may override default conceal settings - to allow more convenient disclosure for
            // special members (stuff members or partners)
            var process = ProcessService.StartProcess(login, LoginProcessType.PasswordReset, processToken);

            return(processToken);
        }
예제 #9
0
        public async Task SendPinForMultiFactor([FromBody] SendPinRequest pinRequest)
        {
            var session = OpContext.OpenSession();
            var process = GetMutiFactorProcess(session, pinRequest.ProcessToken);

            OpContext.ThrowIf(process.CurrentFactor != null, ClientFaultCodes.InvalidAction, "token", "Factor verification pending, the previous process step is not completed.");
            var pendingFactorTypes = process.PendingFactors;

            OpContext.ThrowIf(!pendingFactorTypes.IsSet(pinRequest.FactorType), ClientFaultCodes.InvalidValue, "factortype", "Factor type is not pending in login process");
            var factor = process.Login.ExtraFactors.FirstOrDefault(f => f.FactorType == pinRequest.FactorType);

            OpContext.ThrowIfNull(factor, ClientFaultCodes.ObjectNotFound, "factor",
                                  "Login factor (email or phone) not setup in user account; factor type: {0}", pinRequest.FactorType);
            var processService = OpContext.App.GetService <ILoginProcessService>();
            await processService.SendPinAsync(process, factor);
        }