I've got a working implementation of CustomCredentialsAuth implemented in my ServiceStack app. I can hit the URL with auth credentials, and it works as expected.
In my tests however, I'm not having the same luck.
I'm using RestSharp, and if I disable [Authenticate]
, I can get all of my tests to pass.
Enabling [Authenticate]
and running the tests give me
Expected: OK
But was: Unauthorized
Here is my test. How can I get RestSharp to authenticate for my tests?
using System;
using System.Net;
using FutureState.AppCore.Tests.Integration.Repositories.Fixtures;
using NUnit.Framework;
using RestSharp;
namespace FutureState.AppCore.Tests.Functional.Services
{
[TestFixture]
public class UserServiceInterfaceTests
{
private RestSchemaValidator _restSchemaValidator;
private string _testLoginEmail;
private string _testLoginPassword;
[SetUp]
public void SetUp ()
{
_restSchemaValidator = new RestSchemaValidator();
_testLoginEmail = UserFixture.SystemAccount.Email;
_testLoginPassword = "password";
}
[Test]
public void ShouldGetAListOfUsersAndReturnStatusOk ()
{
// Setup
var client = new RestClient( ServiceTestAppHostBase.BaseUrl );
client.Authenticator = new HttpBasicAuthenticator( _testLoginEmail, _testLoginPassword );
var request = new RestRequest( "/users/", Method.GET ) { RequestFormat = DataFormat.Json };
// Execute
var response = client.Execute( request );
// Assert
Assert.That( response.ErrorMessage, Is.Null );
Assert.That( response.StatusCode, Is.EqualTo( HttpStatusCode.OK ) );
_restSchemaValidator.ValidateResponse( "ExpectedUsersResponse.json", response.Content );
}
[Test]
public void ShouldGetAUserAndReturnStatusOk ()
{
// Setup
var expectedUserId = new Guid( UserFixture.FirstUserId );
var client = new RestClient( ServiceTestAppHostBase.BaseUrl );
client.Authenticator = new HttpBasicAuthenticator( _testLoginEmail, _testLoginPassword );
var request = new RestRequest( "/users/" + expectedUserId, Method.GET ) { RequestFormat = DataFormat.Json };
// Execute
var response = client.Execute( request );
// Assert
Assert.That( response.ErrorMessage, Is.Null );
Assert.That( response.StatusCode, Is.EqualTo( HttpStatusCode.OK ) );
_restSchemaValidator.ValidateResponse( "ExpectedUserResponse.json", response.Content );
}
}
}
I'm using a custom auth provider:
public class CustomCredentialsAuthProvider : CredentialsAuthProvider
{
private readonly IUserService _userService;
private Guid _userId;
public CustomCredentialsAuthProvider ( Container container )
{
_userService = container.Resolve<IUserService>();
}
public override bool TryAuthenticate ( IServiceBase authService, string email, string password )
{
var user = _userService.GetByEmailAddress( email );
user.Password = password; // Add the posted password to the user object before authenticating.
_userId = user.Id;
return _userService.CheckPassword( user );
}
public override void OnAuthenticated ( IServiceBase authService, IAuthSession session, IOAuthTokens tokens, Dictionary<string, string> authInfo )
{
session.Id = _userId.ToString();
//Important: You need to save the session!
authService.SaveSession( session, SessionExpiry );
}
}
And my TestAppHostBase wires up the auth like this.
private void ConfigureAuth ( Container container )
{
//Default route: /auth/{provider}
Plugins.Add( new AuthFeature( () => new AuthUserSession(),
new IAuthProvider[] {
new CustomCredentialsAuthProvider(container)
} ) );
//Default route: /register
Plugins.Add( new RegistrationFeature() );
}
Further development, calling the following code DOES return true for the user, but obviously doesn't pass the session data to the subsequent RestRequest
.
// Calling this returns TRUE for TryAuthenticate
// But doesn't retain the session data for the subsequenet request.
var container = EndpointHost.AppHost.TryResolve<Container>();
var authService = new AuthService();
var customCredentialsAuthProvider = new CustomCredentialsAuthProvider( container );
customCredentialsAuthProvider.TryAuthenticate(authService, _testLoginEmail, _testLoginPassword);