func (h *Service) AuthenticateUser(userIdentifier string, authAdaptorName string, data map[string]interface{}) (kit.User, apperror.Error) { authAdaptor := h.AuthAdaptor(authAdaptorName) if authAdaptor == nil { return nil, &apperror.Err{ Public: true, Code: "unknown_auth_adaptor", Message: "Unknown auth adaptor: " + authAdaptorName} } var user kit.User var err apperror.Error if userIdentifier != "" { user, err = h.FindUser(userIdentifier) if err != nil { return nil, err } else if user == nil { return nil, apperror.New("user_not_found", "Username/Email does not exist ", true) } } userId := "" if user != nil { userId = user.GetStrId() } userId, err = authAdaptor.Authenticate(userId, data) if err != nil { if err.IsPublic() { return nil, err } else { return nil, apperror.Wrap(err, "adaptor_error", true) } } if user == nil { // Query user to get a full user with permissions and profile. user, err = h.FindUser(userId) if err != nil { return nil, err } else if user == nil { return nil, &apperror.Err{ Code: "user_not_found", Message: fmt.Sprintf("User with id %v could not be found", userId), Public: true, } } } if !user.IsActive() { return nil, apperror.New("user_inactive", true) } return user, nil }
func (s *Service) ChangePassword(user kit.User, newPassword string) apperror.Error { adaptor := s.AuthAdaptor("password") if adaptor == nil { return &apperror.Err{ Code: "no_password_adaptor", Message: "The UserService does not have the password auth adaptor", } } passwordAdaptor := adaptor.(*password.AuthAdaptorPassword) if err := passwordAdaptor.ChangePassword(user.GetStrId(), newPassword); err != nil { if err.IsPublic() { return err } else { return apperror.Wrap(err, "adapter_error") } return err } return nil }
func (s *Service) SendConfirmationEmail(user kit.User) apperror.Error { // Check that an email service is configured. mailService := s.registry.EmailService() if mailService == nil { return apperror.New("no_email_service") } conf := s.registry.Config() // Check that sending is enabled. if !conf.UBool("users.sendEmailConfirmationEmail", true) { return nil } // Generate a token. tokenItem, err := s.BuildToken("email_confirmation", user.GetStrId(), time.Time{}) if err != nil { return err } token := tokenItem.GetToken() // Build the confirmation url. confirmationPath := conf.UString("users.emailConfirmationPath") if confirmationPath == "" { return &apperror.Err{ Code: "no_email_confirmation_path", Message: "Config must specify users.emailConfirmationPath", } } if !strings.Contains(confirmationPath, "{token}") { return &apperror.Err{ Code: "invalid_email_confirmation_path", Message: "users.emailConfirmationPath does not contain {token} placeholder", } } confirmationUrl := conf.UString("url") + "/" + strings.Replace(confirmationPath, "{token}", token, -1) // Render email. subject := conf.UString("users.emailConfirmationSubject", "Confirm your Email") var txtContent, htmlContent []byte txtTpl := conf.UString("users.emailConfirmationEmailTextTpl") htmlTpl := conf.UString("users.emailConfirmationEmailHtmlTpl") if txtTpl != "" && htmlTpl != "" { // Check that a template engine is configured. engine := s.registry.TemplateEngine() if engine == nil { return apperror.New("no_template_engine") } data := map[string]interface{}{ "user": user, "token": token, } var err apperror.Error txtContent, err = s.registry.TemplateEngine().BuildFileAndRender(txtTpl, data) if err != nil { return apperror.Wrap(err, "email_confirmation_tpl_error", "Could not render email confirmation tpl") } htmlContent, err = s.registry.TemplateEngine().BuildFileAndRender(htmlTpl, data) if err != nil { return apperror.Wrap(err, "email_confirmation_tpl_error", "Could not render email confirmation tpl") } } else { tpl := `Welcome to Appkit To confirm your email address, please visit %v. ` htmlTpl := `Welcome to Appkit<br><br> To confirm your email address, please visit <a href="%v">this link</a>. ` txtContent = []byte(fmt.Sprintf(tpl, confirmationUrl)) htmlContent = []byte(fmt.Sprintf(htmlTpl, confirmationUrl)) } // Now build the email and send it. email := email.NewMail() email.SetSubject(subject) email.AddBody("text/plain", txtContent) email.AddBody("text/html", htmlContent) email.AddTo(user.GetEmail(), "") if err := mailService.Send(email); err != nil { return err } s.registry.Logger().WithFields(logrus.Fields{ "action": "users.email_confirmation_mail_sent", "email": user.GetEmail(), "user_id": user.GetId(), "token": token, }).Debugf("Password reset email sent to %v for user %v", user.GetEmail(), user.GetId()) return nil }
func (s *Service) SendPasswordResetEmail(user kit.User) apperror.Error { // Check that an email service is configured. mailService := s.registry.EmailService() if mailService == nil { return apperror.New("no_email_service") } hoursValid := 48 // Generate a token. expiresAt := time.Now().Add(time.Hour * time.Duration(hoursValid)) tokenItem, err := s.BuildToken("password_reset", user.GetStrId(), expiresAt) if err != nil { return err } token := tokenItem.GetToken() conf := s.registry.Config() // Build the confirmation url. url := conf.UString("url") if url == "" { return &apperror.Err{ Code: "no_url_set", Message: "Config must specify url", } } resetPath := conf.UString("users.passwordResetPath") if resetPath == "" { return &apperror.Err{ Code: "no_password_reset_path", Message: "Config must specify users.passwordResetPath", } } if !strings.Contains(resetPath, "{token}") { return &apperror.Err{ Code: "invalid_password_reset_path", Message: "users.passwordResetPath does not contain {token} placeholder", } } resetUrl := url + "/" + strings.Replace(resetPath, "{token}", token, -1) // Render email. subject := conf.UString("users.passwordResetSubject", "Password reset") var txtContent, htmlContent []byte txtTpl := conf.UString("users.passwordResetTextTpl") htmlTpl := conf.UString("users.passwordResetHtmlTpl") if txtTpl != "" && htmlTpl != "" { // Check that a template engine is configured. engine := s.registry.TemplateEngine() if engine == nil { return apperror.New("no_template_engine") } data := map[string]interface{}{ "user": user, "token": token, "hours_valid": hoursValid, } var err apperror.Error txtContent, err = s.registry.TemplateEngine().BuildFileAndRender(txtTpl, data) if err != nil { return apperror.Wrap(err, "password_reset_tpl_error", "Could not render password reset tpl") } htmlContent, err = s.registry.TemplateEngine().BuildFileAndRender(htmlTpl, data) if err != nil { return apperror.Wrap(err, "password_reset_tpl_error", "Could not render password reset tpl") } } else { tpl := `Password reset To reset your password, please visit %v. The link will be valid for %v hours. ` htmlTpl := `Password Reset<br><br> To reset your password, please visit <a href="%v">this link</a>.<br> The link will be valid for %v hours. ` txtContent = []byte(fmt.Sprintf(tpl, resetUrl, hoursValid)) htmlContent = []byte(fmt.Sprintf(htmlTpl, resetUrl, hoursValid)) } // Now build the email and send it. email := email.NewMail() email.SetSubject(subject) email.AddBody("text/plain", txtContent) email.AddBody("text/html", htmlContent) email.AddTo(user.GetEmail(), "") if err := mailService.Send(email); err != nil { return err } s.registry.Logger().WithFields(logrus.Fields{ "action": "users.password_reset_requested", "email": user.GetEmail(), "user_id": user.GetId(), "token": token, }).Debugf("Password reset email sent to %v for user %v", user.GetEmail(), user.GetId()) return nil }
func (a *AuthAdaptorOauth) RegisterUser(user kit.User, data map[string]interface{}) (kit.AuthItem, apperror.Error) { serviceName, _ := GetStringFromMap(data, "service") if serviceName == "" { return nil, apperror.New("invalid_data_missing_service") } service := a.services[serviceName] if service == nil { return nil, &apperror.Err{ Code: "unconfigured_service", Message: fmt.Sprintf("The oauth service '%v' was not configured in oauth auth adaptor", serviceName), } } accessToken, _ := GetStringFromMap(data, "access_token") if accessToken == "" { return nil, apperror.New("invalid_data_missing_access_token") } // Exchange access token for long lived token. // This also verifies that the supplied token is valid. appToken, err := service.Exchange(accessToken) if err != nil { return nil, apperror.Wrap(err, "oauth_exchange_token_error", "") } userData, err := service.GetUserData(appToken) if err != nil { return nil, apperror.Wrap(err, "fetch_user_data_failed", "") } if userData.Id == "" { return nil, &apperror.Err{ Code: "fetched_userdata_missing_user_id", Message: "The userData fetched from the service does not contain a userId", } } item := &AuthItemOauth{ Service: serviceName, UserId: user.GetStrId(), ExternalUserId: userData.Id, Token: appToken, } item.Id = serviceName + "_" + userData.Id // Fill in user information. if user.GetEmail() == "" { if userData.Email != "" { user.SetEmail(userData.Email) user.SetIsEmailConfirmed(true) } else { return nil, &apperror.Err{ Code: "oauth_service_insufficient_data_error", Message: fmt.Sprintf("The oauth service %v did not supply the users email, which is required", serviceName), } } } if user.GetUsername() == "" && userData.Username != "" { user.SetUsername(userData.Username) } return item, nil }