コード例 #1
0
ファイル: email.go プロジェクト: itsyouonline/identityserver
//RequestPasswordReset Request a password reset
func (service *IYOEmailAddressValidationService) RequestPasswordReset(request *http.Request, username string, emails []string) (key string, err error) {
	pwdMngr := password.NewManager(request)
	token, err := pwdMngr.NewResetToken(username)
	if err != nil {
		return
	}
	if err = pwdMngr.SaveResetToken(token); err != nil {
		return
	}

	passwordreseturl := fmt.Sprintf("https://%s/login#/resetpassword/%s", request.Host, url.QueryEscape(token.Token))
	templateParameters := struct {
		Url        string
		Username   string
		Title      string
		Text       string
		ButtonText string
		Reason     string
	}{
		Url:        passwordreseturl,
		Username:   username,
		Title:      "It's You Online password reset",
		Text:       "To reset your ItsYou.Online password, click the button below.",
		ButtonText: "Reset password",
		Reason:     "You’re receiving this email because you recently requested to reset your password at ItsYou.Online. If this wasn’t you, please ignore this email.",
	}
	message, err := tools.RenderTemplate(emailWithButtonTemplateName, templateParameters)
	if err != nil {
		return
	}
	go service.EmailService.Send(emails, "ItsYou.Online password reset", message)
	key = token.Token
	return
}
コード例 #2
0
ファイル: login.go プロジェクト: itsyouonline/identityserver
//ResetPassword handler for POST /login/resetpassword
func (service *Service) ResetPassword(w http.ResponseWriter, request *http.Request) {
	values := struct {
		Token    string `json:"token"`
		Password string `json:"password"`
	}{}

	if err := json.NewDecoder(request.Body).Decode(&values); err != nil {
		log.Debug("Error decoding the ResetPassword request:", err)
		http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
		return
	}
	pwdMngr := password.NewManager(request)
	token, err := pwdMngr.FindResetToken(values.Token)
	if err != nil {
		log.Debug("Failed to find password reset token - ", err)
		http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
		return
	}
	err = pwdMngr.Save(token.Username, values.Password)
	if err != nil {
		http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
		return
	}
	if err = pwdMngr.DeleteResetToken(values.Token); err != nil {
		http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
		return

	}
	w.WriteHeader(http.StatusNoContent)
	return
}
コード例 #3
0
//ProcessRegistrationForm processes the user registration form
func (service *Service) ProcessRegistrationForm(w http.ResponseWriter, request *http.Request) {
	response := struct {
		Redirecturl string `json:"redirecturl"`
		Error       string `json:"error"`
	}{}
	values := struct {
		TwoFAMethod    string `json:"twofamethod"`
		Login          string `json:"login"`
		Email          string `json:"email"`
		Phonenumber    string `json:"phonenumber"`
		TotpCode       string `json:"totpcode"`
		Password       string `json:"password"`
		RedirectParams string `json:"redirectparams"`
	}{}
	if err := json.NewDecoder(request.Body).Decode(&values); err != nil {
		log.Debug("Error decoding the registration request:", err)
		http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
		return
	}

	twoFAMethod := values.TwoFAMethod
	if twoFAMethod != "sms" && twoFAMethod != "totp" {
		log.Info("Invalid 2fa method during registration: ", twoFAMethod)
		http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
		return
	}

	totpsession, err := service.GetSession(request, SessionForRegistration, "totp")
	if err != nil {
		log.Error("ERROR while getting the totp registration session", err)
		http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
		return
	}
	if totpsession.IsNew {
		log.Debug("New registration session while processing the registration form")
		http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
		return
	}
	totpsecret, ok := totpsession.Values["secret"].(string)
	if !ok {
		log.Error("Unable to convert the stored session totp secret to a string")
		http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
		return
	}

	valid := user.ValidateUsername(values.Login)
	var phonenumber user.Phonenumber
	if !valid {
		response.Error = "invalid_username_format"
		w.WriteHeader(422)
		json.NewEncoder(w).Encode(response)
		return
	}
	newuser := &user.User{
		Username:       values.Login,
		EmailAddresses: []user.EmailAddress{user.EmailAddress{Label: "main", EmailAddress: values.Email}},
	}
	//validate the username is not taken yet
	userMgr := user.NewManager(request)

	count, err := userMgr.GetPendingRegistrationsCount()
	if err != nil {
		log.Error("Failed to get pending registerations count: ", err)
		http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
		return
	}
	log.Debug("count", count)
	if count >= MAX_PENDING_REGISTRATION_COUNT {
		log.Warn("Maximum amount of pending registrations reached")
		http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
		return
	}

	//we now just depend on mongo unique index to avoid duplicates when concurrent requests are made
	userExists, err := userMgr.Exists(newuser.Username)
	if err != nil {
		http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
		return
	}
	if userExists {
		log.Debug("USER ", newuser.Username, " already registered")
		http.Error(w, http.StatusText(http.StatusConflict), http.StatusConflict)
		return
	}

	if twoFAMethod == "sms" {
		phonenumber = user.Phonenumber{Label: "main", Phonenumber: values.Phonenumber}
		if !phonenumber.IsValid() {
			log.Debug("Invalid phone number")
			w.WriteHeader(422)
			response.Error = "invalid_phonenumber"
			json.NewEncoder(w).Encode(&response)
			return
		}
		newuser.Phonenumbers = []user.Phonenumber{phonenumber}
		// Remove account after 3 days if it still doesn't have a verified phone by then
		duration := time.Duration(time.Hour * 24 * 3)
		expiresAt := time.Now()
		expiresAt = expiresAt.Add(duration)
		newuser.Expire = db.DateTime(expiresAt)
	} else {
		token := totp.TokenFromSecret(totpsecret)
		if !token.Validate(values.TotpCode) {
			log.Debug("Invalid totp code")
			w.WriteHeader(422)
			response.Error = "invalid_totpcode"
			json.NewEncoder(w).Encode(&response)
			return
		}
	}

	userMgr.Save(newuser)
	passwdMgr := password.NewManager(request)
	err = passwdMgr.Save(newuser.Username, values.Password)
	if err != nil {
		log.Error(err)
		if err.Error() != "internal_error" {
			w.WriteHeader(422)
			response.Error = "invalid_password"
			json.NewEncoder(w).Encode(&response)
		} else {
			http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
		}
		return
	}

	if twoFAMethod == "sms" {
		validationkey, err := service.phonenumberValidationService.RequestValidation(request, newuser.Username, phonenumber, fmt.Sprintf("https://%s/phonevalidation", request.Host))
		if err != nil {
			log.Error(err)
			http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
			return
		}
		registrationSession, err := service.GetSession(request, SessionForRegistration, "registrationdetails")
		registrationSession.Values["username"] = newuser.Username
		registrationSession.Values["phonenumbervalidationkey"] = validationkey
		registrationSession.Values["redirectparams"] = values.RedirectParams

		sessions.Save(request, w)
		response.Redirecturl = fmt.Sprintf("https://%s/register#/smsconfirmation", request.Host)
		json.NewEncoder(w).Encode(&response)
		return
	}

	totpMgr := totp.NewManager(request)
	totpMgr.Save(newuser.Username, totpsecret)
	log.Debugf("Registered %s", newuser.Username)
	service.loginUser(w, request, newuser.Username)
}
コード例 #4
0
ファイル: login.go プロジェクト: itsyouonline/identityserver
//ProcessLoginForm logs a user in if the credentials are valid
func (service *Service) ProcessLoginForm(w http.ResponseWriter, request *http.Request) {
	//TODO: validate csrf token
	//TODO: limit the number of failed/concurrent requests

	err := request.ParseForm()
	if err != nil {
		log.Debug("ERROR parsing registration form")
		http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
		return
	}
	values := struct {
		Login    string `json:"login"`
		Password string `json:"password"`
	}{}

	if err = json.NewDecoder(request.Body).Decode(&values); err != nil {
		log.Debug("Error decoding the login request:", err)
		http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
		return
	}

	login := strings.ToLower(values.Login)

	u, err := organization.SearchUser(request, login)
	if err == mgo.ErrNotFound {
		w.WriteHeader(422)
		return
	} else if err != nil {
		log.Error("Failed to search for user: "******"client_id")
	// Remove last 2FA entry if an invalid password is entered
	validcredentials := userexists && validpassword
	if !validcredentials {
		if client != "" {
			l2faMgr := organizationdb.NewLast2FAManager(request)
			if l2faMgr.Exists(client, u.Username) {
				l2faMgr.RemoveLast2FA(client, u.Username)
			}
		}
		w.WriteHeader(422)
		return
	}
	loginSession, err := service.GetSession(request, SessionLogin, "loginsession")
	if err != nil {
		log.Error(err)
		http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
		return
	}
	loginSession.Values["username"] = u.Username
	//check if 2fa validity has passed
	if client != "" {
		l2faMgr := organizationdb.NewLast2FAManager(request)
		if l2faMgr.Exists(client, u.Username) {
			timestamp, err := l2faMgr.GetLast2FA(client, u.Username)
			if err != nil {
				log.Error(err)
				http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
				return
			}
			mgr := organizationdb.NewManager(request)
			seconds, err := mgr.GetValidity(client)
			if err != nil {
				log.Error(err)
				http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
				return
			}
			timeconverted := time.Time(timestamp)
			if timeconverted.Add(time.Second * time.Duration(seconds)).After(time.Now()) {
				service.loginUser(w, request, u.Username)
				return
			}
		}
	}

	sessions.Save(request, w)
	w.WriteHeader(http.StatusNoContent)
}
コード例 #5
0
ファイル: login.go プロジェクト: mohabusama/identityserver
//ProcessLoginForm logs a user in if the credentials are valid
func (service *Service) ProcessLoginForm(w http.ResponseWriter, request *http.Request) {
	//TODO: validate csrf token
	//TODO: limit the number of failed/concurrent requests

	log.Debug(request.RequestURI)

	err := request.ParseForm()
	if err != nil {
		log.Debug("ERROR parsing registration form")
		http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
		return
	}
	values := request.Form

	username := values.Get("login")

	//validate the username exists
	var userexists bool
	userMgr := user.NewManager(request)
	if userexists, err = userMgr.Exists(username); err != nil {
		http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
		return
	}

	var validpassword bool
	passwdMgr := password.NewManager(request)
	if validpassword, err = passwdMgr.Validate(username, values.Get("password")); err != nil {
		http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
		return
	}

	var validtotpcode bool
	totpMgr := totp.NewManager(request)
	if validtotpcode, err = totpMgr.Validate(username, values.Get("totpcode")); err != nil {
		http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
		return
	}
	validcredentials := userexists && validpassword && validtotpcode
	if !validcredentials {
		service.renderLoginForm(w, request, true, request.RequestURI)
		return
	}

	if err := service.SetLoggedInUser(w, request, username); err != nil {
		http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
		return
	}
	sessions.Save(request, w)

	log.Debugf("Successfull login by '%s'", username)

	redirectURL := ""
	queryValues := request.URL.Query()
	endpoint := queryValues.Get("endpoint")
	if endpoint != "" {
		queryValues.Del("endpoint")
		redirectURL = endpoint + "?" + queryValues.Encode()
	}

	http.Redirect(w, request, redirectURL, http.StatusFound)
}
コード例 #6
0
//ProcessRegistrationForm processes the user registration form
func (service *Service) ProcessRegistrationForm(w http.ResponseWriter, request *http.Request) {
	err := request.ParseForm()
	if err != nil {
		log.Debug("ERROR parsing registration form:", err)
		http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
		return
	}

	validationErrors := make([]string, 0, 0)

	values := request.Form

	totpsession, err := service.GetSession(request, SessionForRegistration, "totp")
	if err != nil {
		log.Error("EROR while getting the totp registration session", err)
		http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
		return
	}
	if totpsession.IsNew {
		//TODO: indicate expired registration session
		log.Debug("New registration session while processing the registration form")
		service.ShowRegistrationForm(w, request)
		return
	}
	totpsecret, ok := totpsession.Values["secret"].(string)
	if !ok {
		log.Error("Unable to convert the stored session totp secret to a string")
		http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
		return
	}

	newuser := &user.User{
		Username: values.Get("login"),
		Email:    map[string]string{"registration": values.Get("email")},
	}
	//TODO: validate newuser

	//validate the username is not taken yet
	userMgr := user.NewManager(request)
	//TODO: distributed lock
	userExists, err := userMgr.Exists(newuser.Username)
	if err != nil {
		http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
		return
	}
	if userExists {
		validationErrors = append(validationErrors, "duplicateusername")
		log.Debug("USER ", newuser.Username, " already registered")
		service.renderRegistrationFrom(w, request, validationErrors, totpsecret)
		return
	}

	totpcode := values.Get("totpcode")

	token := totp.TokenFromSecret(totpsecret)
	if !token.Validate(totpcode) {
		log.Debug("Invalid totp code")
		validationErrors = append(validationErrors, "invalidtotpcode")
		service.renderRegistrationFrom(w, request, validationErrors, totpsecret)
		return
	}

	userMgr.Save(newuser)
	passwdMgr := password.NewManager(request)
	passwdMgr.Save(newuser.Username, values.Get("password"))
	totpMgr := totp.NewManager(request)
	totpMgr.Save(newuser.Username, totpsecret)

	log.Debugf("Registered %s", newuser.Username)

	service.SetLoggedInUser(w, request, newuser.Username)
	sessions.Save(request, w)

	http.Redirect(w, request, "/", http.StatusFound)
}