Correct way to authorize an ASMX .NET web service from MVC 4 Project

12,508

Solution 1

In answer to your first question, MVC filters and Web API filters cannot be triggered by ASMX web services.

  1. Action Filters are part of the MVC pipeline, triggered before (or after) an Action Method on a Controller (or API Controller) is executed. They can only be used within the MVC framework.

    Action Filter override a virtual method on a MVC Controller (OnActionExecuting). As only MVC Controllers have such methods, and only the MVC pipeline checks for them

  2. To make matters worse, ASMX services, by default, use SOAP protocol rather than HTTP protocol. SOAP services are not able to access HTTP contexts (e.g. HttpContext.Current.User) or HTTP Frameworks.

    Web services can be configured to use the HTTP protocol. But, even then, MVC specific attributes are of no help to you.


Ways to Authenticate legacy ASMX services

  • Ideal way is to add a Service Reference to your MVC 4 project, calling your ASMX method like any class library method from an [Authorize] secured Action Method or Web API method.

    This way, you can leverage your MVC or Web API Authentication filters.

  • If you prefer to secure your ASMX service directly, you can check to HttpContext.Current.User with Forms Authentication by configuring your ASMX service to use HTTP protocol.

in your web.config

<location path="SecuredMethod.asmx">
  <system.web>
    <webServices>
      <protocols>
        <add name="HttpGet"/>
        <add name="HttpPost"/>
      </protocols>
    </webServices>
  </system.web>
</location> 

Solution 2

I think creating custom attribute filter for Authorization will be good idea. You can create your costume filter that customizes authorization as like this.

namespace CustomeFilters
{
    class CustomAuthorize : AuthorizeAttribute
    {
        private const string _securityParameter = "someCredentials"; // Name of the url parameter. 
        public override void OnAuthorization(AuthorizationContext filterContext)
        {
            if (Authorize(filterContext))
            {
                return;
            }

            HandleUnauthorizedRequest(filterContext);
        }


    protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
    {
        //Your logic for unauthorized access
        HttpRequestBase request = filterContext.RequestContext.HttpContext.Request;
        string deviceId = request.Params[_securityParameter]; //Your may have values in request headers

        if (!string.IsNullOrEmpty(_securityParameter ))
        {
            base.HandleUnauthorizedRequest(filterContext);

        }

        //You can also check if request is authorized as basic authentication or not
        //if(!filterContext.HttpContext.User.Identity.IsAuthenticated)
    }


    private bool Authorize(AuthorizationContext actionContext)
    {
            HttpRequestBase request = actionContext.RequestContext.HttpContext.Request;

            // Your authorisation logic goes here..                                     

           //actionContext.RequestContext.HttpContext.Response.StatusCode = 400;

           //actionContext.Result = new JsonResult { JsonRequestBehavior = JsonRequestBehavior.AllowGet, Data = "Request from invalid device !" };

            bool success = <true/false>;//Acording to authorisation logic
            return success;
    }
}

It will be used like this

    [CustomAuthorize]
    public ActionResult Test()
    { 
        ViewBag.Message = "Hello World.";

        return View();
    }

Here you are inheriting Authorize attribute from MVC authorization. It is overriding two methods:

  1. OnAuthorisation : here your authorisation logic goes.Here it is checking for handelling unauthorized request.
  2. HandleUnauthorizedRequest :here logic for handelling unauthorized access goes.It is calling it's parrent's class HandleUnauthorizedRequest to get executed for handling unauthorized access.

Solution 3

First part of your Question:

is using MVC attributes an acceptable way of authorizing web service called on an ASMX web service?

As per @DaveAlperovich

MVC filters and Web API filters cannot be triggered by ASMX web services.

But from this SO answer

Since ASMX are also server by the ASP.NET pipeline, you could just use HttpModules, which give you a lot of control on the way in and the way out.

Here's a reference and an example: http://msdn.microsoft.com/en-us/library/aa719858%28VS.71%29.aspx

If you want to make it very "MVC-like" then you would write a custom http module that check the webservice for attributes such as [Authorize] etc. Since ASP.NET MVC is open source you may just use parts of that as a reference how they check for attributes etc and then build it into your HTTPModule.

Link to SO Question

So Still i couldn't find a well Official documented regarding your First question and i still doubt that certain events don't fire for a web service while using the MVC attributes

Update

While coming to ASMX (source)

uses XML Information Set for its message format, and relies on application layer protocols, most notably Hypertext Transfer Protocol (HTTP) or Simple Mail Transfer Protocol (SMTP), for message negotiation and transmission

From Scott Hanselman Blog the request is by default not handled by the ASP.NET MVC routing mechanism

Why doesn't ASP.NET MVC grab the request? Two reasons. First, there's an option on RouteCollection called RouteExistingFiles. It's set to false by default which causes ASP.NET MVC to automatically skip routing when a file exists on disk.

Second Qst:

is there a better/more efficient way of authorizing web service method calls?

you may use credentials sent in the SOAP header to authorizing the web service

Here is an example:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Services;
using System.Web.Services.Protocols;

namespace AuthExample
{

    public class Authentication : SoapHeader
    {
        public string User;
        public string Password;
    }

    /// <summary>
    /// Summary description for webrusterapi
    /// </summary>
    [WebService(Namespace = "http://xxxx.xxx")]
    [WebServiceBinding(ConformsTo = Profiles.BProfile1)]
    [System.ComponentModel.ToolboxItem(false)]
    public class Webrusterapi: System.Web.Services.WebService
    {
        public Authentication authHeader;

        [WebMethod]
        public string HelloWorld()
        {
            return "Hello World";
        }

        [WebMethod]
        [SoapHeader("authHeader")]
        public string HelloWorldWithCredentials()
        {
            if (authHeader.User != "Foouser" & authHeader.Password != "barPassword")
            {
                new SoapException("Fault occurred", SoapException.ClientFaultCode);
            }
            return string.Format("Hello {0}", authHeader.User);
        }
    }
}

Solution 4

.ASMX Service and AuthorizeAttribute

The MVC and Web API pipeline are not directly compatible with the older style of .ASMX web services. This is why those attributes do not fire when you place them on your web methods. Depending on your code base you could convert (rewrite) your code to the Web API 2 platform which is the new recommended way to write services. This has the following advantages over the traditional web services (.asmx).

  1. Data Format - The client can determine the format of the data that is received. Currently the 2 out of the box supported formats are xml and json. This can be significantly easier to work with for a client as the payload sent and received is usually much simpler not to mention light weight (the SOAP envelop used in .asmx services is very bloated.)
  2. Action Filters - You can take advantage of the Authorize attribute as well as custom Action Filters to execute common action preprocessing and post processing.
  3. Intentions with HTTP Verb - Actions become based on HTTP instead of SOAP. You can utilize the http methods to give direct meaning to your exposed web methods (GET, POST, PUT, DELETE).
  4. Ease of use across development platforms - All other things being equal it is much simpler to write against a web api method than an ASMX method because the payload and responses are easier to translate due to the lack of bloat. Some of the standard types are also easier to translate which are usually included in the WSDL definition language like nullable types and .net DateTime instances.

The question then becomes "Should you convert your existing code?" That depends on:

  • Do you have existing clients that already call your code base that would also need to be converted? That might not make this possible if those clients are outside of your control (if these calling clients are created by your customers for example).
  • The size or number of methods that you already have created. If you are just starting your project it might still be easy to convert over to Web Api but if you already have a substantial code base with unit tests this might not be cost effective.
  • If you already have a contract defined with outside parties around your code. It is possible to create the definitions in a WSDL and have client development and server side development run concurrently based on that contract, if this is the case you would need to convince your client side developer(s)/parties to convert to a Web API contract but this might not be possible.

What I would avoid is writing a wrapper in Web API that calls through to the Web Service.

  • It adds a physical layer between calls (crossing another network boundary) which increases the delay between message sent and response received
  • It adds another layer of code that you have to create and maintain
  • Additional (unnecessary) layers also like this make it very easy to inadvertently introduce defects when you have to implement changes

.ASMX Authorization

Lets now assume that you want to continue with the .ASMX web services and address the question How can you execute Authorization on a web service.

Traditional / defacto

The traditional way to authenticate is to include the authentication information in the SOAP header. This can be easily accomplished using the existing SoapHeaderAttribute.

  • Place the SoapHeaderAttribute on your web method(s)
  • Create an Authentication object that will contain the passed in arguments used for authentication
  • Write the authentication method

I prefer to create an abstract base service that my other services inherit from. This should create a little less duplicate code. Here is a full example without the authentication details. In this example I use a traditional user name and password but really it can be anything (token, a password hash, HMAC info, etc) and as that is a little out of scope for the question I will not get into authentication details.

using System.Web.Services;
using System.Web.Services.Protocols;

public abstract class AuthorizedWebService : System.Web.Services.WebService 
{
    // authentication info
    public Authentication Authentication { get; set; }
    // execute the actual authentication and authorization check
    protected virtual void Authorize()
    {
        // check the Authentication instance object (passed in credentials)
        // if not authenticate or authorized
        // throw new System.Security.Authentication.AuthenticationException();
    }
}
// authentication info
public class Authentication : SoapHeader
{
    public string Username { get; set; }
    public string Password { get; set; }
}

[WebService(Namespace = "http://tempuri.org/")]
public class MyTraditionalWebService : AuthorizedWebService
{

    [WebMethod(Description = "Some web method.")]
    [SoapHeader("Authentication")]
    public string HelloWorld()
    {
        base.Authorize();
        return "Hello " + base.Authentication.Username;
    }
}

Active Directory Authentication

You can use Active Directory authentication. In c# a client would then pass in the credentials using the NetworkCredential class. Essentially what the client does is apply the authentication credentials to the HTTP header. I found this rather good SO answer on what the NetworkCredential class will actually translate into when making an HTTP call. You have to configure IIS so that authentication and authorization occur before the request reaches your method. You could also execute custom code for the authorization directly in your web methods (similar to above) but not for the authentication.

Forms Authentication

As for Forms Authentication there is no good way to do this with Web Services that has any advantage over the above specified Traditional / defacto way. However, if you already have a web site setup which (now) includes your .asmx services then you could include authorization for the service in the web.config assuming that the client has already authenticated to your site.

Custom HttpModule

You could also write a custom HttpModule which handles the authentication and possible Authorization. The pro of this approach is you decouple the business logic in the web service from the authentication/authorization. This is a double edged sword though as you will have to maintain a module that parses the url and also the intended method to see if the request is authorized. This can lead to a fragile coupling.

Share:
12,508

Related videos on Youtube

Jimbo
Author by

Jimbo

Updated on September 16, 2022

Comments

  • Jimbo
    Jimbo about 1 year

    I have an ASP.NET MVC application that has a .asmx web service

    I wrote an action filter attribute that I wanted to use on web methods on the web service, to check the Request headers for a UserID and Password, and throw an unauthorized response code if invalid or not present.

    However, they dont appear to get called! Breakpoints just dont get hit.

    Firstly, is using MVC attributes an acceptable way of authorizing web service called on an ASMX web service?

    Secondly, is there a better/more efficient way of authorizing web service method calls?

    • Igor
      Igor over 7 years
      Do these answers help you get to where you need to go?
  • Pranav Labhe
    Pranav Labhe over 7 years
    Yes, i am seeing now, There might be some more efficient and good approaches for this.I am just giving my thought on question.
  • Dave Alperovich
    Dave Alperovich over 7 years
    Action Filters override a virtual method on a MVC Controller (OnActionExecuting). As only MVC Controllers have such methods, and only the MVC pipeline checks for them, how would an ASMX method execute it?
  • Krsna Kishore
    Krsna Kishore over 7 years
    @DaveAlperovich thanks for the info , even i also stated that i am not sure how autenticate it is,
  • Dave Alperovich
    Dave Alperovich over 7 years
    yes, you did. And to be fair, this is a subject few people understand well.
  • Krsna Kishore
    Krsna Kishore over 7 years
    @DaveAlperovich in order to understand well any Offical document stating that MVC filters and Web API filters cannot be triggered by ASMX web services , so that few can become more
  • Dave Alperovich
    Dave Alperovich over 7 years
    I understand your point. A good rule to go by is whether a feature is language specific or Framework specific. Attributes of ASMX and MVC will never be compatible. On the other hand, attributes (like http modules) that are consistent throughout the ASP.NET framework or consistant through C#, can be re-used across frameworks. I certainly admire your research tenacity...
  • Dave Alperovich
    Dave Alperovich over 7 years
    Custom HttpModule is an interesting option. Wouldn't provide exactly what OP asks for (using MVC filters), but functionally, can get everything looking for.
  • Igor
    Igor over 7 years
    ASMX services, by default, use SOAP protocol rather than HTTP protocol - SOAP is the message format and sits higher in the network stack (presentation) than HTTP which is how the message is communicated. So I do not believe this statement is accurate, ASMX still use the http protocol to communicate but maybe I misinterpreted your statement. SOAP services are not able to access HTTP contexts - I have yet to have encountered this, you can access the HttpContext.Current in your .asmx service although I am not sure what good it does unless you are using windows auth. or forms within a webap.
  • Igor
    Igor over 7 years
    I found a link. Excerpt: ... uses XML Information Set for its message format, and relies on application layer protocols, most notably Hypertext Transfer Protocol (HTTP) or Simple Mail Transfer Protocol (SMTP), for message negotiation and transmission.
  • Dave Alperovich
    Dave Alperovich over 7 years
    @Igor, soon ad I get to the office, I will read this. Am very intrigued.
  • Krsna Kishore
    Krsna Kishore over 7 years
    Igor thats a nyc point you got so i would like to elaborate more on this and @dave you have mentioned this to my comment Attributes of ASMX and MVC will never be compatible. On the other hand, attributes (like http modules) that are consistent throughout the ASP.NET framework or consistant through C#, can be re-used across frameworks , so based on igor comment as ASMX is using the HTTP modules that are consistent throughout the ASP.NET Framework or C# but again , here we are dealing with the Topic which donesn't have a certain proper Docs . so we will be learning by our Experience ...
  • Krsna Kishore
    Krsna Kishore over 7 years
    @DaveAlperovich , just out of curiosity , if ASMX is relying on Application layer protocols (HTTP) , don't you think that MVC Attributes will be called over ASMX as it is following the Common Protocol (HTTP) .
  • Dave Alperovich
    Dave Alperovich over 7 years
    @Webruster No, they will not. While ASMX services can use http protocol, they are NOT part of MVC framework. Filter attributes override Methods on MVC Controllers. ASMX framework has no such methods.
  • Krsna Kishore
    Krsna Kishore over 7 years
    @DaveAlperovich Yes, I do agree that ASMX Services are not part of MVC, but my point is MVC attributes can be authorized the web serivces using ASMX because ASMX is using a common Protocol (i.e. HTTP) for Both MVC and ASMX
  • Dave Alperovich
    Dave Alperovich over 7 years
    @Webruster, no they cannot. Even using the same protocol, the ASMX framework has no methods or listeners compatible with MVC filters.
  • Krsna Kishore
    Krsna Kishore over 7 years
    @DaveAlperovich Yes, you are right and the Actual reason for it is ,Why doesn't ASP.NET MVC grab the request? Two reasons. First, there's an option on RouteCollection called RouteExistingFiles. It's set to false by default which causes ASP.NET MVC to automatically skip routing when a file exists on disk. this was stated from the Scott Blog . so in the end not e the above might be the reason for MVC filters can't authorize the over the ASMX web service
  • Igor
    Igor over 7 years
    Correct. Although MVC sits on top of ASP.NET (which also uses the HTTP protocol) it uses its own framework extending ASP.NET. You can think of it as 2 columns with 2 (possible) common base layers. At the bottom you have the HTTP Protocol (again, not always required as you can do asmx over smtp), then the asp.net framework, then you have 2 independent columns on top of that one for the MVC framework and another for the ASMX web services framework. (wish I could insert a pic). So the columns have a common base but are independent of each other.
  • Igor
    Igor over 7 years
    So the end result is types defined in the MVC column (the MVC framework) are (out of the box) should not be used by other frameworks like the ASMX web services because they will never be called.