Saturday, October 31, 2015

IIS Log files

Have you ever wondered about logs of IIS. Yes, they do exist, providing a lot of vital information about the applications that we have hosted in the IIS. For each website we host in IIS, it's logs are created and can be configured for different settings. 

To test it, let's create a sample ASP.Net application and we name it as IISLogging and host it in the IIS. Browse the application to check it is hosted properly.

Now in order to check the logs, click on the website and select the Logging option in the right pane and double click to open it. 




Clicking the option will open the logging settings section. Here we can check what is the location of the IIS logs for our website, which we have hosted. Also it provides different configuration settings for generation of the log files.



Now go to the location as displayed and check out the log files getting generated. Now here you can see different folders getting generated with the name prefix as W3SVC and a number added to it as a suffix. 

How to identify the website IIS log file ?

Now here you may have different folders getting generated. But which one is yours. In order to identify this, go to the website in the IIS and click Advance Settings for the website. This will open it's settings windows. 


Check the ID property. This is the ID of the website in IIS and your log file folder will have this number as the suffix attached to it. So in our case the log file folder is W3SVC2. Check the folder and we can see the log file generated for it.

So we have our log files generated based on the dates here. 

How to analyze IIS log files ?

In order to read these log files in effective way, different tools are available which include log parser lizard and weblog expert. So happy logging now...!!!

Saturday, October 17, 2015

Basic Authentication in Web-API at HOST level using Authentication Filters


In our previous discussions, we discussed about the basics about the security in asp.net web api. If you have not read that then i would recommend you to read that first here, as it will act as a base of where and how to apply the security in asp.net web api, as we discussed the basics of security. Also we discussed the concept of how we can Implement Basic Authentication in ASP.Net Web API at Host level (IIS)

Continuing on same lines, we will implement basic authentication using the concept of Authentication filters. An authentication filter is nothing but creating an attribute and applying it on the class or method.
To start with, we will create an empty ASP.Net application. Next, we add an API controller called SampleController and derive it from ApiController to make it a web-api type controller. Also we add a method named GetList() to return list of string values. So our class will look like the following.

 public class SampleController : ApiController
 {
        public IEnumerable<String> GetList()
        {
          return new String[] { "value1", "value2" };
        }
 }


Let's browse the api method using the path: and see the results. We can easily view the results. No username/password required.

Anybody, who knows the url of your api, can make call to it and use the method and we would like to restrict this, so that only people who are authorized to access the system, should get access to the api method. So, in order to apply security on our method, we need to do the following:
  1. Create an authentication filter, which is nothing but a class derived from IAuthenticationFilter interface and Attribute class. It will implement the following IAuthenticate methods. These are:
    • AuthenticateAsync
    • ChallengeAsync
  2. Apply this filter as an attribute on the method or the controller, on which we would like to add the security.
  3. Apply the Authorize attribute along with this attribute. 
How the security process will work ? 

When the IAuthenticationFilter is applied, AuthenticateAsync is the method which will receive any request for the web-api methods and check for the credentials(if they are present), in the request header. There are 3 possible scenarios:

Case 1 - No credentials provided: Client request has not sent any credentials. In such a case, authentication filter will do nothing and pass it on to Authorize attribute to handle it. Since there were no credentials, and identity was NOT authenticated, the request is rejected with Code 401 unauthorized result.

Case 2 - Invalid credentials provided: In case the client has provided invalid credentials, the ErrorResult property of the current HttpAuthenticationContext instance is set with UnauthorizedResult. An authentication challenge is added to the Result property of the current HttpAuthenticationContext instance. This is done by the ChallengeAsync method of the IAuthenticationFilter interface.

Case 3 - Valid credentials provided: If the credentials provided in the request header are valid, then a valid ClaimPrincipal will be generated and will be assigned to the Principle property of the current HttpAuthenticationContext instance. Further the Authorize attribute will check if the Identity is established for the request, then allow the access to the method or controller. 

So one of the major role of Authorize attribute is checking whether an identity for the user has been established or not by the authentication filters, which were executed previously in the pipeline. If it is not established, then return 401 Unauthorized error, else request will be allowed to access the method.
So let's start by creating the authentication filter class. We will name it as BasicAuthenticationFilter. We will derive it from Attribute class and IAuthenticationFilter. So our code will look like the following:


using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Security.Claims;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Web;
using System.Web.Http;
using System.Web.Http.Filters;
using System.Web.Http.Results;
namespace AuthenticationFilter
{
    public class BasicAuthenticationFilter : Attribute, IAuthenticationFilter
    {
        private readonly String realm;
        public Boolean AllowMultiple { get { return false; } }
        public BasicAuthenticationFilter(string realm)
        {
             this.realm = "realm=" + realm;
        }
        public Task AuthenticateAsync(HttpAuthenticationContext context, CancellationToken cancellationToken)
        {
             var currentRequest = context.Request;
             if (currentRequest.Headers.Authorization != null && currentRequest.Headers.Authorization.Scheme == "Basic")
            {
                 Encoding encoding = Encoding.GetEncoding("iso-8859-1");
                 var headerData = encoding.GetString(Convert.FromBase64String(currentRequest.Headers.Authorization.Parameter));
                 var credentials = headerData.Split(':');
                 var userId = credentials[0].Trim();
                 var pwd = credentials[1].Trim();
                 if (userId == "jasminder" && pwd == "jasminder")
                 {
                    var claims = new List<Claim>()
                    {
                                new Claim(ClaimTypes.Name, "auth")
                    };
                    var id = new ClaimsIdentity(claims, "Basic");
                    var principal = new ClaimsPrincipal(new[] { id });
                    context.Principal = principal;
                 }
                else
                {
                    context.ErrorResult = new UnauthorizedResult(new AuthenticationHeaderValue[0], context.Request);
                }
            }
              return Task.FromResult(0);
     }
    public async Task ChallengeAsync(HttpAuthenticationChallengeContext context, CancellationToken cancellationToken)
        {
            HttpResponseMessage result = await context.Result.ExecuteAsync(cancellationToken);
            if (result.StatusCode == HttpStatusCode.Unauthorized)
            {
                result.Headers.WwwAuthenticate.Add(new AuthenticationHeaderValue("Basic", "realm=" + this.realm));
            }
            context.Result = new ResponseMessageResult(result);
        }
    } 
}


Attribute class will make it possible to apply it as an attribute on the method or controller. AuthenticateAsync will be used for authenticating the request credentials, if presentand ChallengeAsync will be used to prepare the final HttpResponse, based on the result of ExecuteAsync method of the current HttpAuthenticationChallengeContexts' context.

Now simply apply this filter and the authorize attribute on our method, like any other attribute:


using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;

namespace AuthenticationFilter
{
    public class SampleController : ApiController
    {
        [BasicAuthenticationFilter("testRealm")]
        [Authorize]
        public IEnumerable<String> GetList()
        {
            return new String[] { "value1", "value2" };
        }
    }
}

Now let's test the 3 cases that we discussed above.

Case 1:  Run the application and you will be prompted for a username/password.


Click Cancel and see that you get the message Authorization has been denied for this request.


This was because, when the authentication filter received the request, no credentials were provided. So it passed on the request to the Authorize attribute. Due to absence of an authenticated principle, it rejected the request and this message was received.

Case 2:  Run the api again and this time enter invalid credentials. This time, the authenticate method will check for the credentials. Since the credentials were not valid, it will set the ErrorResult property of the current HttpAuthenticationContext instance.




Case 3:  Since the credentials were invalid, it will again ask for the credentials. This time, we will provide the valid credentials and see the code get's executed:



This time the credentials were valid. So an Identity is established for the current request (as above) and method result is returned.

Now a point that I have mentioned above, about the ExecuteAsync is very important. This means that when ever the ChallengeAsync method get's executed, it will get the HttpResponse generated for the request, from the ExecuteAsync method. So if the ExecuteAsync method says that the request is UnAuthorized request, we will check the response and set the basic authentication challenge in the response. Read a very important point here, from the official asp.net web-api. It says:

It's important to understand that ChallengeAsync is called before the HTTP response is created, and possibly even before the controller action runs. When ChallengeAsync is called, context.Result contains an IHttpActionResult, which is used later to create the HTTP response. So when ChallengeAsync is called, you don't know anything about the HTTP response yet. The ChallengeAsync method should replace the original value of context.Result with a new IHttpActionResult. This IHttpActionResult must wrap the original context.Result.

The best way to test this point is to remove the Authorize attribute and add a debugger to the ChallengeAsync and the api method we need to access. When we run the request, we can see that the ExecuteAsync will be able to execute the api method (in our case it is GetList) and HttpStatusCode as OK will be returned. This means the HttpResponse was successfully generated for the request, by the ExecuteAsync method. Had we applied the Authorize attribute, it would have returned UnAuthorized status and based on the results it returned, we can then add our authentication challenge on the response from the ExecuteAsync.

So this was how we can implement the basic authentication filter using web-api Authentication filters. Hope you enjoyed reading it. Happy coding...!!!

Saturday, October 3, 2015

The type or namespace name 'IAuthenticationFilter' could not be found

IAuthenticationFilter interface is used for inheritance, while creating the security filters for web-api. If you face the issue:

The type or namespace name 'IAuthenticationFilter' could not be found

just add the namespace: System.Web.Http.Filters and it will work.  Happy coding...!!!