mardi 30 juin 2015

How to test Web.API method with RestSharp passing in ClaimsPrincipal

I'm having a bit of trouble with a specific implementation of testing out my Web.API methods using RestSharp. I have been very successful in performing POSTS and GETS in my open (non-secured) methods. However, when I have to send in a token to determine access I have problems.

Here is the implementation:

I am using OWIN middleware for my Web.API. The client must post to a token service in order to get the given Token that contains their claims. All of this has been working fine.

In my test my Initializer has the following code that posts to the token service and gets back the token. This works wonderfully - returns back the token as advertised:

 [TestInitialize]
    public void SetupTest()
    {

        _verificationErrors = new StringBuilder();

        _client = new RestClient
        {
            BaseUrl = new Uri(ConfigurationManager.AppSettings["ServicesBaseUrl"])
        };

        _serviceRequestPrepender = ConfigurationManager.AppSettings["ServiceRequestPrepender"];

        // Initialize this by getting the user token put back for all of the tests to use.
        var request = new RestRequest(string.Format("{0}{1}", _serviceRequestPrepender, ConfigurationManager.AppSettings["TokenEndpointPath"]), Method.POST);

        // Add header stuff
        request.AddParameter("Content-Type", "application/x-www-form-urlencoded", ParameterType.HttpHeader);
        request.AddParameter("Accept", "application/json", ParameterType.HttpHeader);

        // Add request body
        _userName = "{test student name}";
        _password = "{test student password}";
        _userGuid = "{this is a guid value!!}";

        _clientIdentifier = ConfigurationManager.AppSettings["ClientIdentifier"];
        _applicationId = ConfigurationManager.AppSettings["ApplicationId"];

        string encodedBody = string.Format("grant_type=password&username={0}&password={1}&scope={2} {3} {4} {0}"
                                           , _userName, _password, _clientIdentifier, _userGuid, _applicationId);
        request.AddParameter("application/x-www-form-urlencoded", encodedBody, ParameterType.RequestBody);


        // execute the request
        IRestResponse response = _client.Execute(request);

        // Make sure everything is working as promised.
        Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
        Assert.IsTrue(response.ContentLength > 0);

        _token = new JavaScriptSerializer().Deserialize<Token>(response.Content).access_token;

    }

Next is the following code that calls a Web.API method which passes the given token along to another Web.API method where I'm performing a GET to extract some information from my service.

        [TestMethod]
    public void GetUserProfileTest()
    {

        // Arrange
        var request = new RestRequest(string.Format("{0}{1}", _serviceRequestPrepender, "api/UserProfiles/UserProfiles/Get/{appId}/{userId}/{username}"), Method.GET);

        // Add header stuff
        request.AddParameter("Content-Type", "application/json", ParameterType.HttpHeader);
        request.AddParameter("Accept", "/application/json", ParameterType.HttpHeader);
        request.AddParameter("Authorization", string.Format("{0} {1}", "Bearer", _token));

        request.AddUrlSegment("appId", "1");
        request.AddUrlSegment("userId", _userGuid);
        request.AddUrlSegment("username", _userName);

        // execute the request
        IRestResponse response = _client.Execute(request);

        // Make sure everything is working as promised.
        Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
        Assert.IsTrue(response.ContentLength > 0); // do more when working

    }

Next, the service is called, but I have decorated the Web.API method with a custom access security check. This is a VERY simple security check in that it only checks to see if the token is valid and not expired. Here is the IsAuthorized method of that attribute:

        protected override bool IsAuthorized(System.Web.Http.Controllers.HttpActionContext actionContext)
    {
        // Custom Code here
        return ValidityChecker.IsTokenValid(actionContext);
    }

The ValidityChecker is a simple class that only checks to see if the token is valid:

    public class TokenValidityChecker
{
    public ClaimsPrincipal PrincipalWithClaims { get; private set; }

    /// <summary>
    /// Extracts out the ability to perform token checking since all Token checking attributes will need t his.
    /// </summary>
    /// <param name="actionContext"></param>
    /// <returns></returns>
    public bool IsTokenValid(System.Web.Http.Controllers.HttpActionContext actionContext)
    {
        bool result = false;

        var principal = actionContext.RequestContext.Principal;
        if (principal.GetType() == typeof(ClaimsPrincipal))
        {
            PrincipalWithClaims = (ClaimsPrincipal)principal;
            result = PrincipalWithClaims.Identity.IsAuthenticated;
        }

        // Custom Code here
        return result;
    }
}

So, with the background in place - here is the question. As you can see, normally, when the service is called the ValidityChecker will receive an HttpActionContext. Along with that, the RequestContext.Principal of that HttpActionContext will normally be of type ClaimsPrincipal.

However, when running from a unit test and using RestSharp it is, of course, a WindowsPrincipal.

Is there a way using RestSharp to make that a ClaimsPrincipal? I've tried to ensure the token is included in the header using the Authorization parameter, but have not had any luck.

Aucun commentaire:

Enregistrer un commentaire