Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- using System;
- using System.Security.Authentication;
- using System.Text;
- using System.Web.Mvc;
- using TenForce.Execution.Framework;
- using TenForce.Execution.Api2.Implementation;
- namespace TenForce.Execution.Web.Filters
- {
- /// <summary>
- /// This class defines a custom Authentication attribute that can be applied on controllers.
- /// This results in authentication occurring on all actions that are beeing defined in the controller
- /// who implements this filter.
- /// </summary>
- [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
- public class AuthenticationFilter : ActionFilterAttribute
- {
- #region IAuthorizationFilter Members
- /// <summary>
- /// This function get's called by the Mvc framework prior to performing any actions on
- /// the controller. The function will check if a call is authorized by the caller.
- /// The function will extract the username and password from the HTTP headers send by
- /// the caller and will validate these against the database to see if there is a valid
- /// account for the user.
- /// If the user can be found in the database, operations will resume, otherwise the action
- /// is canceled.
- /// </summary>
- /// <param name="filterContext">The context for the filter.</param>
- public override void OnActionExecuting(ActionExecutingContext filterContext)
- {
- // Call the base operations first.
- base.OnActionExecuting(filterContext);
- // Surround the entire authentication process with a try-catch to prevent errors from
- // breaking the code.
- try
- {
- // Extract the custom authorization header from the HTTP headers.
- string customAuthHeader = Encoding.UTF8.GetString(Convert.FromBase64String(filterContext.RequestContext.HttpContext.Request.Headers["TenForce-Auth"]));
- // Split the header in the subcomponents.
- string[] components = customAuthHeader.Split('|');
- // Check if both components are present.
- if (components.Length >= 2)
- {
- // This header consists of 2 parts, the username and password, seperate by a vertical pipe.
- string username = components[0] ?? string.Empty;
- string password = components[1] ?? string.Empty;
- string databaseId = Authenticator.ConstructDatabaseId(filterContext.HttpContext.Request.RawUrl);
- // Validate the user against the database.
- if (Authenticator.Authenticate(username, password, databaseId))
- {
- // The request is valid, so add the custom header to inform the request was
- // authorized.
- AllowRequest(filterContext);
- return;
- }
- throw new InvalidCredentialException(@"The provided username & password combination is invalid. Username : " + username);
- }
- // If we reach this point, the authorization request is no longer valid.
- throw new InvalidCredentialException(@"Insufficient parameters supplied for a valid authentication.");
- }
- catch (Exception ex)
- {
- // Log the exception that has occurred.
- Logger.Log(GetType(), ex);
- // Cancel the request, as we could not properly process it.
- CancelRequest(filterContext);
- }
- }
- #endregion
- #region Private Methods
- /// <summary>
- /// Cancels the Athorization and adds the custom tenforce header to the response to
- /// inform the caller that his call has been denied.
- /// </summary>
- /// <param name="authContext">The authorizationContxt that needs to be canceled.</param>
- private static void CancelRequest(ActionExecutingContext authContext)
- {
- authContext.Result = new HttpUnauthorizedResult();
- if (!authContext.RequestContext.HttpContext.Request.ServerVariables[@"SERVER_SOFTWARE"].Contains(@"Microsoft-IIS/7."))
- authContext.HttpContext.Response.AddHeader(@"Tenforce-RAuth", @"DENIED");
- else
- authContext.HttpContext.Response.Headers.Add(@"Tenforce-RAuth", @"DENIED");
- }
- /// <summary>
- /// Allows the Authorization and adds the custom tenforce header to the response to
- /// inform the claler that his call has been allowed.
- /// </summary>
- /// <param name="authContext">The authorizationContext that needs to be allowed.</param>
- private static void AllowRequest(ActionExecutingContext authContext)
- {
- authContext.Result = null;
- if (!authContext.RequestContext.HttpContext.Request.ServerVariables[@"SERVER_SOFTWARE"].Contains(@"Microsoft-IIS/7."))
- authContext.HttpContext.Response.AddHeader(@"Tenforce-RAuth", @"OK");
- else
- authContext.HttpContext.Response.Headers.Add(@"Tenforce-RAuth", @"OK");
- }
- #endregion
- }
- }
- /// <summary>
- /// This function is called before running each test and configures the various properties
- /// of the test class so that each test will run with the same settings initialy.
- /// The function will configure the Mock Framework object so that they simulate a proper
- /// web request on the ActionFilter of a Controller.
- /// </summary>
- [SetUp]
- protected void TestSetup()
- {
- // Construct the Mock object required for the test.
- HttpRequest = new Mock<HttpRequestBase>();
- HttpResponse = new Mock<HttpResponseBase>();
- HttpContext = new Mock<HttpContextBase>();
- ActionContext = new Mock<ActionExecutingContext>();
- Filter = new Web.Filters.AuthenticationFilter();
- // Configure the properties to modify the headers, request and response
- // objects starting from the HttpContext base object.
- // Also create the custom header collection and set the test URI.
- ActionContext.SetupGet(c => c.HttpContext).Returns(HttpContext.Object);
- HttpContext.SetupGet(r => r.Request).Returns(HttpRequest.Object);
- HttpContext.SetupGet(r => r.Response).Returns(HttpResponse.Object);
- HttpResponse.SetupGet(x => x.Headers).Returns(new System.Net.WebHeaderCollection());
- HttpRequest.SetupGet(r => r.RawUrl).Returns(@"http://test.tenforce.tst");
- }
- /// <summary>
- /// <para>This test will call the ActionFilter and perform a standard authorization request against the
- /// database using the credentials of the system administrator account. The test relies on the MoQ
- /// framework to mock several of the key components in the MVC Framework such as the HttpRequest,
- /// HttpResponse and HttpContext objects.</para>
- /// <para>The test expects the authentication to succeed, and relies on the IIS6 implementation.</para>
- /// </summary>
- [Test, MaxDuration]
- public void SuccessfullAuthenticationOnIis6()
- {
- // Configure the Authentication header of the request, so that a valid authentication
- // can take place. We want valid login credentials when the filter requests the header.
- HttpRequest.SetupGet(r => r.Headers).Returns(new System.Net.WebHeaderCollection { { @"TenForce-Auth", CorrectAuthToken } });
- HttpRequest.SetupGet(r => r.ServerVariables).Returns(
- new System.Collections.Specialized.NameValueCollection { { @"SERVER_SOFTWARE", @"Microsoft-IIS/6.0" } });
- HttpResponse.SetupGet(r => r.Headers).Returns(new System.Collections.Specialized.NameValueCollection());
- HttpResponse.Setup(r => r.AddHeader(@"TenForce-RAuth", @"OK"));
- // Call the action on the filter and check the response.
- Filter.OnActionExecuting(ActionContext.Object);
- // Check the ActionResult to null and that the response header contains the correct value.
- Assert.IsTrue(ActionContext.Object.Result == null);
- Assert.IsTrue(ActionContext.Object.HttpContext.Response.Headers["TenForce-RAuth"].Equals(@"OK"));
- }
- HttpResponse.Setup(r => r.AddHeader(It.IsAny<string>(), It.IsAny<string>())).Callback<string, string>((x,y) => HttpResponse.Object.Headers.Add(x, y));
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement