Skip to content
This repository has been archived by the owner on Dec 9, 2020. It is now read-only.

Commit

Permalink
Password checking algorithm is now configurable
Browse files Browse the repository at this point in the history
* added IPasswordHasher interface and respective public property to IOAuthServiceLocator
* updated unit tests and sample code
  • Loading branch information
naasir committed Oct 9, 2012
1 parent 3400c43 commit 985fe43
Show file tree
Hide file tree
Showing 9 changed files with 75 additions and 40 deletions.
16 changes: 15 additions & 1 deletion samples/MVC3Sample/OAuthServiceLocator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ public class OAuthServiceLocator : IOAuthServiceLocator
private readonly IConsumerRepository _consumerRepository = new ConsumerRepository();
private readonly IResourceOwnerRepository _resourceOwnerRepository = new ResourceOwnerRepository();
private readonly IOAuthIssuer _oAuthIssuer = new OAuthIssuer();
private readonly IConfiguration _configuration = new Configuration();
private readonly IConfiguration _configuration = new Configuration();
private readonly IPasswordHasher _passwordHasher = new MD5PasswordHasher();

public IConsumerRepository ConsumerRepository
{
Expand All @@ -34,6 +35,11 @@ public IConfiguration Configuration
{
get { return _configuration; }
}

public IPasswordHasher PasswordHasher
{
get { return _passwordHasher; }
}
}

public class ConsumerRepository : IConsumerRepository
Expand Down Expand Up @@ -122,6 +128,14 @@ public int AuthorizationTokenExpirationLength
}
}

public class MD5PasswordHasher : IPasswordHasher
{
public bool CheckPassword(string plaintext, string hashed)
{
return plaintext.ToHash() == hashed;
}
}

public class Consumer : IConsumer
{
public string ApplicationName { get; set; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ public class PasswordTokenRequestAuthorizerTest
[Test]
public void WhenClientIdIsInvalid_ThenThrowsException()
{
var mocker = new AutoMoqer();
var mocker = new AutoMoqer();
mocker.MockServiceLocator();
mocker.GetMock<IOAuthRequest>().Setup(x => x.ContentType).Returns(ContentType.FormEncoded);
mocker.GetMock<IOAuthRequest>().Setup(x => x.ClientId).Returns("");
mocker.GetMock<IOAuthRequest>().Setup(x => x.ClientSecret).Returns("clientsecret");
Expand All @@ -41,7 +42,8 @@ public void WhenClientIdIsInvalid_ThenThrowsException()
[Test]
public void WhenClientSecretIsInvalid_ThenThrowsException()
{
var mocker = new AutoMoqer();
var mocker = new AutoMoqer();
mocker.MockServiceLocator();
mocker.GetMock<IOAuthRequest>().Setup(x => x.ContentType).Returns(ContentType.FormEncoded);
mocker.GetMock<IOAuthRequest>().Setup(x => x.ClientId).Returns("clientid");
mocker.GetMock<IOAuthRequest>().Setup(x => x.Username).Returns("username");
Expand All @@ -67,7 +69,8 @@ public void WhenClientSecretIsInvalid_ThenThrowsException()
[Test]
public void WhenUsernameIsInvalid_ThenThrowsException()
{
var mocker = new AutoMoqer();
var mocker = new AutoMoqer();
mocker.MockServiceLocator();
mocker.GetMock<IOAuthRequest>().Setup(x => x.ContentType).Returns(ContentType.FormEncoded);
mocker.GetMock<IOAuthRequest>().Setup(x => x.ClientId).Returns("clientid");
mocker.GetMock<IOAuthRequest>().Setup(x => x.ClientSecret).Returns("clientsecret");
Expand All @@ -94,14 +97,15 @@ public void WhenUsernameIsInvalid_ThenThrowsException()
[Test]
public void WhenPasswordIsInvalid_ThenThrowsException()
{
var mocker = new AutoMoqer();
var mocker = new AutoMoqer();
mocker.MockServiceLocator();
mocker.GetMock<IOAuthRequest>().Setup(x => x.ContentType).Returns(ContentType.FormEncoded);
mocker.GetMock<IOAuthRequest>().Setup(x => x.ClientId).Returns("clientid");
mocker.GetMock<IOAuthRequest>().Setup(x => x.ClientSecret).Returns("clientsecret");
mocker.GetMock<IOAuthRequest>().Setup(x => x.Username).Returns("username");
mocker.GetMock<IOAuthRequest>().Setup(x => x.GrantType).Returns(GrantType.Password);
mocker.GetMock<IConsumerRepository>().Setup(x => x.GetByClientId("clientid")).Returns(new ConsumerImpl { ClientId = "clientid", Secret = "clientsecret" });
mocker.GetMock<IResourceOwnerRepository>().Setup(x => x.GetByUsername(1, "username")).Returns(new ResourceOwnerImpl { Username = "username", Password = "pass" });
mocker.GetMock<IResourceOwnerRepository>().Setup(x => x.GetByUsername(0, "username")).Returns(new ResourceOwnerImpl { Username = "username", Password = "pass" });
mocker.GetMock<IOAuthRequest>().Setup(x => x.Password).Returns("password");

var authorizer = mocker.Resolve<PasswordTokenRequestAuthorizer>();
Expand All @@ -121,7 +125,8 @@ public void WhenPasswordIsInvalid_ThenThrowsException()
[Test]
public void WhenContentTypeIsInvalid_ThenThrowsException()
{
var mocker = new AutoMoqer();
var mocker = new AutoMoqer();
mocker.MockServiceLocator();
mocker.GetMock<IOAuthRequest>().Setup(x => x.ContentType).Returns(ContentType.Json);
mocker.GetMock<IOAuthRequest>().Setup(x => x.ClientId).Returns("clientid");
mocker.GetMock<IOAuthRequest>().Setup(x => x.ClientSecret).Returns("clientsecret");
Expand All @@ -148,14 +153,16 @@ public void WhenContentTypeIsInvalid_ThenThrowsException()
[Test]
public void EnsureApplicationIsApproved()
{
var mocker = new AutoMoqer();
var mocker = new AutoMoqer();
mocker.MockServiceLocator();
mocker.GetMock<IOAuthRequest>().Setup(x => x.ContentType).Returns(ContentType.FormEncoded);
mocker.GetMock<IOAuthRequest>().Setup(x => x.ClientId).Returns("clientid");
mocker.GetMock<IOAuthRequest>().Setup(x => x.ClientSecret).Returns("clientsecret");
mocker.GetMock<IOAuthRequest>().Setup(x => x.Username).Returns("username");
mocker.GetMock<IOAuthRequest>().Setup(x => x.GrantType).Returns(GrantType.Password);
mocker.GetMock<IConsumerRepository>().Setup(x => x.GetByClientId("clientid")).Returns(new ConsumerImpl { ConsumerId = 1, ClientId = "clientid", Secret = "clientsecret" });
mocker.GetMock<IResourceOwnerRepository>().Setup(x => x.GetByUsername(1, "username")).Returns(new ResourceOwnerImpl { ResourceOwnerId = 2, Username = "username", Password = "password".ToHash() });
mocker.GetMock<IResourceOwnerRepository>().Setup(x => x.GetByUsername(1, "username")).Returns(new ResourceOwnerImpl { ResourceOwnerId = 2, Username = "username", Password = "password".ToHash() });
mocker.GetMock<IPasswordHasher>().Setup(x => x.CheckPassword("password", "password".ToHash())).Returns(true);
mocker.GetMock<IOAuthRequest>().Setup(x => x.Password).Returns("password");
mocker.SetInstance<IOAuthIssuer>(new OAuthIssuer());

Expand All @@ -169,17 +176,19 @@ public void EnsureApplicationIsApproved()
[Test]
public void ReturnsAuthorizedToken()
{
var mocker = new AutoMoqer();
var mocker = new AutoMoqer();
mocker.MockServiceLocator();
mocker.GetMock<IOAuthRequest>().Setup(x => x.ContentType).Returns(ContentType.FormEncoded);
mocker.GetMock<IOAuthRequest>().Setup(x => x.ClientId).Returns("clientid");
mocker.GetMock<IOAuthRequest>().Setup(x => x.ClientSecret).Returns("clientsecret");
mocker.GetMock<IOAuthRequest>().Setup(x => x.Username).Returns("username");
mocker.GetMock<IOAuthRequest>().Setup(x => x.GrantType).Returns(GrantType.Password);
mocker.GetMock<IConsumerRepository>().Setup(x => x.GetByClientId("clientid")).Returns(new ConsumerImpl { ConsumerId = 1, ClientId = "clientid", Secret = "clientsecret" });
mocker.GetMock<IResourceOwnerRepository>().Setup(x => x.GetByUsername(1, "username")).Returns(new ResourceOwnerImpl { ResourceOwnerId = 2, Username = "username", Password = "password".ToHash() });
mocker.GetMock<IResourceOwnerRepository>().Setup(x => x.GetByUsername(1, "username")).Returns(new ResourceOwnerImpl { ResourceOwnerId = 2, Username = "username", Password = "password".ToHash() });
mocker.GetMock<IPasswordHasher>().Setup(x => x.CheckPassword("password", "password".ToHash())).Returns(true);
mocker.GetMock<IOAuthRequest>().Setup(x => x.Password).Returns("password");
mocker.GetMock<IConfiguration>().Setup(x => x.AccessTokenExpirationLength).Returns(3600);
mocker.SetInstance<IOAuthIssuer>(new OAuthIssuer());
mocker.GetMock<IConfiguration>().Setup(x => x.AccessTokenExpirationLength).Returns(3600);
mocker.GetMock<IOAuthServiceLocator>().Setup(x => x.Issuer).Returns(new OAuthIssuer());

var authorizer = mocker.Resolve<PasswordTokenRequestAuthorizer>();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -207,17 +207,19 @@ public void WhenDataIsValid_ThenNewTokenIsCreated()
[Test]
public void ReturnsAuthorizedToken()
{
var mocker = new AutoMoqer();
var mocker = new AutoMoqer();
mocker.MockServiceLocator();
mocker.GetMock<IOAuthRequest>().Setup(x => x.ContentType).Returns(ContentType.FormEncoded);
mocker.GetMock<IOAuthRequest>().Setup(x => x.ClientId).Returns("clientid");
mocker.GetMock<IOAuthRequest>().Setup(x => x.ClientSecret).Returns("clientsecret");
mocker.GetMock<IOAuthRequest>().Setup(x => x.Username).Returns("username");
mocker.GetMock<IOAuthRequest>().Setup(x => x.GrantType).Returns(GrantType.Password);
mocker.GetMock<IConsumerRepository>().Setup(x => x.GetByClientId("clientid")).Returns(new ConsumerImpl { ConsumerId = 1, ClientId = "clientid", Secret = "clientsecret" });
mocker.GetMock<IResourceOwnerRepository>().Setup(x => x.GetByUsername(1, "username")).Returns(new ResourceOwnerImpl { ResourceOwnerId = 2, Username = "username", Password = "password".ToHash() });
mocker.GetMock<IResourceOwnerRepository>().Setup(x => x.GetByUsername(1, "username")).Returns(new ResourceOwnerImpl { ResourceOwnerId = 2, Username = "username", Password = "password".ToHash() });
mocker.GetMock<IPasswordHasher>().Setup(x => x.CheckPassword("password", "password".ToHash())).Returns(true);
mocker.GetMock<IOAuthRequest>().Setup(x => x.Password).Returns("password");
mocker.GetMock<IConfiguration>().Setup(x => x.AccessTokenExpirationLength).Returns(3600);
mocker.SetInstance<IOAuthIssuer>(new OAuthIssuer());
mocker.GetMock<IConfiguration>().Setup(x => x.AccessTokenExpirationLength).Returns(3600);
mocker.GetMock<IOAuthServiceLocator>().Setup(x => x.Issuer).Returns(new OAuthIssuer());

var authorizer = mocker.Resolve<PasswordTokenRequestAuthorizer>();

Expand Down
3 changes: 2 additions & 1 deletion src/OAuth2Provider.Tests/MockHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ public static void MockServiceLocator(this AutoMoqer mocker)
mocker.GetMock<IOAuthServiceLocator>().Setup(x => x.Issuer).Returns(mocker.GetMock<IOAuthIssuer>().Object);
mocker.GetMock<IOAuthServiceLocator>().Setup(x => x.Configuration).Returns(mocker.GetMock<IConfiguration>().Object);
mocker.GetMock<IOAuthServiceLocator>().Setup(x => x.ConsumerRepository).Returns(mocker.GetMock<IConsumerRepository>().Object);
mocker.GetMock<IOAuthServiceLocator>().Setup(x => x.ResourceOwnerRepository).Returns(mocker.GetMock<IResourceOwnerRepository>().Object);
mocker.GetMock<IOAuthServiceLocator>().Setup(x => x.ResourceOwnerRepository).Returns(mocker.GetMock<IResourceOwnerRepository>().Object);
mocker.GetMock<IOAuthServiceLocator>().Setup(x => x.PasswordHasher).Returns(mocker.GetMock<IPasswordHasher>().Object);
}
}
}
32 changes: 13 additions & 19 deletions src/OAuth2Provider/Authorization/PasswordTokenRequestAuthorizer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,14 @@

namespace OAuth2Provider.Authorization
{
public class PasswordTokenRequestAuthorizer : IAuthorizeTokenRequest
{
private readonly IConsumerRepository _consumerRepository;
private readonly IResourceOwnerRepository _resourceOwnerRepository;
private readonly IOAuthIssuer _issuer;
private readonly IConfiguration _configuration;
public class PasswordTokenRequestAuthorizer : IAuthorizeTokenRequest
{
private readonly IOAuthServiceLocator _serviceLocator;
private readonly ILog _logger = LogManager.GetLogger(typeof(PasswordTokenRequestAuthorizer));

public PasswordTokenRequestAuthorizer(IConsumerRepository consumerRepository, IResourceOwnerRepository resourceOwnerRepository, IOAuthIssuer issuer, IConfiguration configuration)
{
_consumerRepository = consumerRepository;
_resourceOwnerRepository = resourceOwnerRepository;
_issuer = issuer;
_configuration = configuration;
public PasswordTokenRequestAuthorizer(IOAuthServiceLocator serviceLocator)
{
_serviceLocator = serviceLocator;
}

public Token Authorize(IOAuthRequest request)
Expand All @@ -33,23 +27,23 @@ public Token Authorize(IOAuthRequest request)
throw new OAuthException(ErrorCode.InvalidRequest, "Invalid content type.");

//Make sure consumer is valid
var consumer = _consumerRepository.GetByClientId(request.ClientId);
var consumer = _serviceLocator.ConsumerRepository.GetByClientId(request.ClientId);
if (consumer == null)
throw new OAuthException(ErrorCode.InvalidClient, "Client credentials are invalid");

if (consumer.Secret != request.ClientSecret)
throw new OAuthException(ErrorCode.InvalidClient, "User credentials are invalid");

//Make sure resource owner is valid
var resourceOwner = _resourceOwnerRepository.GetByUsername(consumer.ConsumerId, request.Username);
var resourceOwner = _serviceLocator.ResourceOwnerRepository.GetByUsername(consumer.ConsumerId, request.Username);
if (resourceOwner == null)
throw new OAuthException(ErrorCode.InvalidClient, "User credentials are invalid");

if (resourceOwner.Password != request.Password.ToHash())
if (!_serviceLocator.PasswordHasher.CheckPassword(request.Password, resourceOwner.Password))
throw new OAuthException(ErrorCode.InvalidClient, "User credentials are invalid");

//Make sure consumer is approved by resource owner
_resourceOwnerRepository.ApproveConsumer(resourceOwner.ResourceOwnerId, consumer.ConsumerId);
_serviceLocator.ResourceOwnerRepository.ApproveConsumer(resourceOwner.ResourceOwnerId, consumer.ConsumerId);

var data = new TokenData
{
Expand All @@ -60,9 +54,9 @@ public Token Authorize(IOAuthRequest request)

return new Token
{
AccessToken = _issuer.GenerateAccessToken(data),
RefreshToken = _issuer.GenerateRefreshToken(data),
ExpiresIn = _configuration.AccessTokenExpirationLength
AccessToken = _serviceLocator.Issuer.GenerateAccessToken(data),
RefreshToken = _serviceLocator.Issuer.GenerateRefreshToken(data),
ExpiresIn = _serviceLocator.Configuration.AccessTokenExpirationLength
};
}
}
Expand Down
3 changes: 2 additions & 1 deletion src/OAuth2Provider/IOAuthServiceLocator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ public interface IOAuthServiceLocator
IConsumerRepository ConsumerRepository { get; }
IResourceOwnerRepository ResourceOwnerRepository { get; }
IOAuthIssuer Issuer { get; }
IConfiguration Configuration { get; }
IConfiguration Configuration { get; }
IPasswordHasher PasswordHasher { get; }
}
}
13 changes: 13 additions & 0 deletions src/OAuth2Provider/IPasswordHasher.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
namespace OAuth2Provider
{
public interface IPasswordHasher
{
/// <summary>
/// Compares the specified plaintext value with the hash supplied.
/// </summary>
/// <param name="plaintext">The plaintext password.</param>
/// <param name="hashed">The hashed password.</param>
/// <returns>True if the password is correct, otherwise false.</returns>
bool CheckPassword(string plaintext, string hashed);
}
}
1 change: 1 addition & 0 deletions src/OAuth2Provider/OAuth2Provider.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@
<Compile Include="IConfiguration.cs" />
<Compile Include="IConsumer.cs" />
<Compile Include="IOAuthMessage.cs" />
<Compile Include="IPasswordHasher.cs" />
<Compile Include="Issuer\OAuthIssuer.cs" />
<Compile Include="Issuer\TokenData.cs" />
<Compile Include="Regexs.cs" />
Expand Down
4 changes: 2 additions & 2 deletions src/OAuth2Provider/Request/TokenRequest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ public Token Authorize()
case OAuth2Provider.GrantType.RefreshToken:
authorizer = new RefreshTokenRequestAuthorizer(ServiceLocator.ConsumerRepository, ServiceLocator.ResourceOwnerRepository, ServiceLocator.Issuer, ServiceLocator.Configuration);
break;
case OAuth2Provider.GrantType.Password:
authorizer = new PasswordTokenRequestAuthorizer(ServiceLocator.ConsumerRepository, ServiceLocator.ResourceOwnerRepository, ServiceLocator.Issuer, ServiceLocator.Configuration);
case OAuth2Provider.GrantType.Password:
authorizer = new PasswordTokenRequestAuthorizer(ServiceLocator);
break;
case OAuth2Provider.GrantType.AuthorizationCode:
authorizer = new AuthorizationCodeAuthorizer(ServiceLocator.Issuer, ServiceLocator.Configuration);
Expand Down

0 comments on commit 985fe43

Please sign in to comment.