Beispiel #1
0
func (r *userRepo) Create(tx repo.Transaction, usr user.User) (err error) {
	if usr.ID == "" {
		return user.ErrorInvalidID
	}

	_, err = r.get(tx, usr.ID)
	if err == nil {
		return user.ErrorDuplicateID
	}
	if err != user.ErrorNotFound {
		return err
	}

	if !user.ValidEmail(usr.Email) {
		return user.ErrorInvalidEmail
	}

	// make sure there's no other user with the same Email
	_, err = r.getByEmail(tx, usr.Email)
	if err == nil {
		return user.ErrorDuplicateEmail
	}
	if err != user.ErrorNotFound {
		return err
	}

	err = r.insert(tx, usr)
	return err
}
Beispiel #2
0
func (r *userRepo) Update(tx repo.Transaction, usr user.User) error {
	if usr.ID == "" {
		return user.ErrorInvalidID
	}

	if !user.ValidEmail(usr.Email) {
		return user.ErrorInvalidEmail
	}

	// make sure this user exists already
	_, err := r.get(tx, usr.ID)
	if err != nil {
		return err
	}

	// make sure there's no other user with the same Email
	otherUser, err := r.getByEmail(tx, usr.Email)
	if err != user.ErrorNotFound {
		if err != nil {
			return err
		}
		if otherUser.ID != usr.ID {
			return user.ErrorDuplicateEmail
		}
	}

	err = r.update(tx, usr)
	if err != nil {
		return err
	}

	return nil
}
Beispiel #3
0
func (m *UserManager) insertNewUser(tx repo.Transaction, email string, emailVerified bool) (user.User, error) {
	if !user.ValidEmail(email) {
		return user.User{}, user.ErrorInvalidEmail
	}

	var err error
	if _, err = m.userRepo.GetByEmail(tx, email); err == nil {
		return user.User{}, user.ErrorDuplicateEmail
	}
	if err != user.ErrorNotFound {
		return user.User{}, err
	}

	userID, err := m.userIDGenerator()
	if err != nil {
		return user.User{}, err
	}

	usr := user.User{
		ID:            userID,
		Email:         email,
		EmailVerified: emailVerified,
		CreatedAt:     m.Clock.Now(),
	}

	err = m.userRepo.Create(tx, usr)
	if err != nil {
		return user.User{}, err
	}
	return usr, nil
}
Beispiel #4
0
func (h *SendResetPasswordEmailHandler) handlePOST(w http.ResponseWriter, r *http.Request) {
	data := sendResetPasswordEmailData{}
	h.fillData(r, &data)

	if !user.ValidEmail(data.Email) {
		h.errPage(w, "Please supply a valid email addresss.", http.StatusBadRequest, &data)
		return
	}

	data.EmailSent = true
	execTemplate(w, h.tpl, data)

	// We spawn this in new goroutine because we don't want anyone using timing
	// attacks to guess if an email address exists or not.
	go h.emailer.SendResetPasswordEmail(data.Email, data.RedirectURLParsed, data.ClientID)
}
Beispiel #5
0
func handleRegisterFunc(s *Server, tpl Template) http.HandlerFunc {

	errPage := func(w http.ResponseWriter, msg string, code string, status int) {
		data := registerTemplateData{
			Error:   true,
			Message: msg,
			Code:    code,
		}
		execTemplateWithStatus(w, tpl, data, status)
	}

	internalError := func(w http.ResponseWriter, err error) {
		log.Errorf("Internal Error during registration: %v", err)
		errPage(w, "There was a problem processing your request.", "", http.StatusInternalServerError)
	}

	idx := makeConnectorMap(s.Connectors)

	return func(w http.ResponseWriter, r *http.Request) {
		err := r.ParseForm()
		if err != nil {
			internalError(w, err)
			return
		}

		// verify the user has a valid code.
		key := r.Form.Get("code")
		sessionID, err := s.SessionManager.ExchangeKey(key)
		if err != nil {
			errPage(w, "Please authenticate before registering.", "", http.StatusUnauthorized)
			return
		}

		// create a new code for them to use next time they hit the server.
		code, err := s.SessionManager.NewSessionKey(sessionID)
		if err != nil {
			internalError(w, err)
			return
		}
		ses, err := s.SessionManager.Get(sessionID)
		if err != nil || ses == nil {
			return
		}

		var exists bool
		exists, err = remoteIdentityExists(s.UserRepo, ses.ConnectorID, ses.Identity.ID)
		if err != nil {
			internalError(w, err)
			return
		}

		if exists {
			// we have to create a new session to be able to run the server.Login function
			newSessionKey, err := s.NewSession(ses.ConnectorID, ses.ClientID,
				ses.ClientState, ses.RedirectURL, ses.Nonce, false, ses.Scope)
			if err != nil {
				internalError(w, err)
				return
			}
			// make sure to clean up the old session
			if err = s.KillSession(code); err != nil {
				internalError(w, err)
			}

			// finally, we can create a valid redirect URL for them.
			redirURL, err := s.Login(ses.Identity, newSessionKey)
			if err != nil {
				internalError(w, err)
				return
			}

			registerURL := newLoginURLFromSession(
				s.IssuerURL, ses, true, []string{}, "")

			execTemplate(w, tpl, registerTemplateData{
				RemoteExists: &remoteExistsData{
					Login:    redirURL,
					Register: registerURL.String(),
				},
			})

			return
		}

		// determine whether or not this is a local or remote ID that is going
		// to be registered.
		idpc, ok := idx[ses.ConnectorID]
		if !ok {
			internalError(w, fmt.Errorf("no such IDPC: %v", ses.ConnectorID))
			return
		}
		_, local := idpc.(*connector.LocalConnector)

		// Does the email comes from a trusted provider?
		trustedEmail := ses.Identity.Email != "" && idpc.TrustedEmailProvider()
		validate := r.Form.Get("validate") == "1"
		formErrors := []formError{}
		email := strings.TrimSpace(r.Form.Get("email"))

		// only auto-populate the first time the page is GETted, not on
		// subsequent POSTs
		if email == "" && r.Method == "GET" {
			email = ses.Identity.Email
		}

		password := r.Form.Get("password")
		if validate {
			if email == "" || !user.ValidEmail(email) {
				formErrors = append(formErrors, formError{"email", "Please supply a valid email"})
			}
			if local && password == "" {
				formErrors = append(formErrors, formError{"password", "Please supply a valid password"})
			}
		}

		data := registerTemplateData{
			Code:     code,
			Email:    email,
			Password: password,
			Local:    local,
		}

		// If there are form errors or this is the initial request
		// (i.e. validate==false), and we are not going to auto-submit a
		// trusted email, then show the form.
		if (len(formErrors) > 0 || !validate) && !trustedEmail {
			data.FormErrors = formErrors
			if !validate {
				execTemplate(w, tpl, data)
			} else {
				execTemplateWithStatus(w, tpl, data, http.StatusBadRequest)
			}
			return
		}

		var userID string
		if local {
			userID, err = registerFromLocalConnector(
				s.UserManager,
				s.SessionManager,
				ses,
				email, password)
		} else {
			if trustedEmail {
				// in the case of a trusted email provider, make sure we are
				// getting the email address from the session, not from the
				// query string, to prevent forgeries.
				email = ses.Identity.Email
			}
			userID, err = registerFromRemoteConnector(
				s.UserManager,
				ses,
				email,
				trustedEmail)
		}
		if err == user.ErrorDuplicateEmail {
			// In this case, the user probably just forgot that they registered.
			connID, err := getConnectorForUserByEmail(s.UserRepo, email)
			if err != nil {
				internalError(w, err)
			}
			loginURL := newLoginURLFromSession(
				s.IssuerURL, ses, false, []string{connID}, "login-maybe")
			if err = s.KillSession(code); err != nil {
				log.Errorf("Error killing session: %v", err)
			}
			http.Redirect(w, r, loginURL.String(), http.StatusSeeOther)
			return
		}

		if err != nil {
			formErrors := errToFormErrors(err)
			if len(formErrors) > 0 {
				data.FormErrors = formErrors
				execTemplate(w, tpl, data)
				return
			}
			if err == user.ErrorDuplicateRemoteIdentity {
				errPage(w, "You already registered an account with this identity", "", http.StatusConflict)
				return
			}
			internalError(w, err)
			return
		}
		ses, err = s.SessionManager.AttachUser(sessionID, userID)
		if err != nil {
			internalError(w, err)
			return
		}

		usr, err := s.UserRepo.Get(nil, userID)
		if err != nil {
			internalError(w, err)
			return
		}

		if !trustedEmail {
			_, err = s.UserEmailer.SendEmailVerification(usr.ID, ses.ClientID, ses.RedirectURL)

			if err != nil {
				log.Errorf("Error sending email verification: %v", err)
			}
		}

		w.Header().Set("Location", makeClientRedirectURL(
			ses.RedirectURL, code, ses.ClientState).String())
		w.WriteHeader(http.StatusSeeOther)
		return
	}
}