Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Password Resetting in Servicestack
using CORE.Kernel.ExtensionMethods;
using CORE.Models;
using ServiceStack.Common;
using ServiceStack.Common.Web;
using ServiceStack.FluentValidation;
using ServiceStack.ServiceHost;
using ServiceStack.ServiceInterface;
using ServiceStack.ServiceInterface.Auth;
using ServiceStack.ServiceInterface.ServiceModel;
using ServiceStack.ServiceInterface.Validation;
using ServiceStack.WebHost.Endpoints;
using System;
using System.Collections.Generic;
using System.Runtime.Serialization;
using Validation;
namespace CORE
{
[Route("/passwordreset")]
[Route("/api/auth/passwordreset")]
public class PasswordResetRequest
{
public string Email { get; set; }
public string Id { get; set; }
public string newpassword { get; set; }
}
public class passwordResetResponse
{
public string id { get; set; }
public bool passwordChanged { get; set; }
public bool valid { get; set; }
}
[DefaultRequest(typeof(PasswordResetRequest))]
internal class PasswordResetService : AppServiceBase
{
public IUserAuthRepository UserAuthRepo { get; set; }
//Called when a password reset link is clicked.
public object Get(PasswordResetRequest request)
{
if (!ValidationLibrary.validate(request.Id, ValidationLibrary.GUID))
return new passwordResetResponse() { valid = false };
//Display Change Password Screen
var resetrequest = Cache.Get<PasswordResetRequest>(request.Id);
var response = new passwordResetResponse();
response.valid = !(resetrequest == null);
response.id = request.Id;
return response;
}
//Called when the password request is initiated.
public string Post(PasswordResetRequest request)
{
if (request.Email == null)
{
this.Response.StatusCode = 400;
return "You must provide an email address.";
}
if (UserAuthRepo.GetUserAuthByUserName(request.Email) == null)
{
this.Response.StatusCode = 400;
return "Email Address not registered.";
}
request.Id = Guid.NewGuid().ToString();
Cache.Add<PasswordResetRequest>(request.Id, request, new TimeSpan(1, 0, 0));
var email = new Email();
email.to = new List<EmailAddress>();
email.to.Add(new EmailAddress() { email = request.Email });
email.from = new EmailAddress() { email = "core@cornwall.ac.uk" };
email.subject = "Password Reset";
email.body = "<p>Uh Oh! Have you forgotten your password?</p><p>Somebody asked for a password reminder, if it was you click this link to reset it now.</p><p><a href=\""+AppConfig.getAppConfig().appURL+"/passwordreset?id=" + request.Id + "\">"+AppConfig.getAppConfig().appURL+"/passwordreset?id=" + request.Id + "</a></p><p>This link is valid for 1 hour</p><p>If you've remember your password, or you didn't request a reset, you can ignore this email</p><p>Regards</p><p>Cornwall College</p>";
email.TrackingId = request.Id;
PublishMessage<Email>(email);
return "An email has been sent with a link to reset your password.";
}
public passwordResetResponse Put(PasswordResetRequest request)
{
if (!ValidationLibrary.validate(request.Id, ValidationLibrary.GUID))
return new passwordResetResponse() { valid = false };
if (!ValidationLibrary.validate(request.newpassword, ValidationLibrary.UserPassword))
return new passwordResetResponse() { valid = false };
//Changes the password
var resetrequest = Cache.Get<PasswordResetRequest>(request.Id);
var response = new passwordResetResponse();
if (resetrequest == null)
{
response.valid = false;
return response;
}
else
{
response.valid = true;
}
var existingUser = UserAuthRepo.GetUserAuthByUserName(resetrequest.Email);
if (existingUser == null)
{
return new passwordResetResponse() { valid = false };
}
UserAuthRepo.UpdateUserAuth(existingUser, existingUser, request.newpassword);
response.passwordChanged = true;
Cache.Remove(resetrequest.Id);
return response;
}
}
}
@allenkiwi
Copy link

allenkiwi commented Dec 23, 2013

Hi Mike,

I like your solution, and it's exactly what I am looking for! Thanks for share the code.

If you don't mind, could you also put the code of:

  1. PublishMessage(email);
  2. ValidationLibrary.validate()

So I can complete my own test version of it?

Or you could email me the code at allenkiwi@gmail.com

Many thanks in advance,

Allen

@PaulSnijders
Copy link

PaulSnijders commented Feb 23, 2014

There is a security issue here!

Line 103 should be:
if (resetrequest == null || resetrequest.Email != request.Email)

otherwise it is possible to ask a password reset from one user and then reset the password of another user. Nice!

@glaidler
Copy link

glaidler commented Mar 16, 2016

Just my 2 pence: Further to this, on Line 69-71, I wouldn't return an error if it's an unknown email address as this leaves you open to brute force "find a valid email address" attacks - return should be a success and on the client give a message like "If you're a valid user you'll receive an email..."

@GuerrillaCoder
Copy link

GuerrillaCoder commented Aug 20, 2018

Thanks for idea of using cache to store reset request

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment