Search code examples
c#restwcfrestrictionssecurity-roles

WCF service: restrictions for WebGet and WebInvoke with AD - security roles for a website with anonymous access


I wrote a WCF service with WebGet and WebInvoke methods. It works so far (after a lots of trial and error :-)

But now I have troubles getting restrictions using AD security roles to work. I need to restrict the access to the WebInvoke method SetBoxPosition, which is used to write data into my service.

The only restrictions that work are the one from the web.config <location> below for "ZES_R" and "ZES_RW". But as the names suggest: ZES_R should read and ZES_RW read and write (post) ...

I have tried various code from the vast of the internet ... ie. from https://ramanisandeep.wordpress.com/2014/11/24/wcf-security-how-do-i-restrict-user-access-to-methods-in-wcf/

[PrincipalPermission(SecurityAction.Demand, Role = "ZES_rw")]
public String SetBoxPosition(PostBoxData postBoxData)
{ .....

or making a custom ServiceAuthorizationManager.

public class MyServiceAuthorizationManager : ServiceAuthorizationManager
{
        protected override bool CheckAccessCore(OperationContext operationContext)
        {
            try
            {
                ServiceSecurityContext securityContext = operationContext.ServiceSecurityContext;
                WindowsIdentity callingIdentity = securityContext.WindowsIdentity;

                WindowsPrincipal principal = new WindowsPrincipal(callingIdentity);
                return principal.IsInRole("rdm-WEB-Reas_rw");
            }
            catch (Exception)
            {
                return false;
            }
        }
    }

While debugging the function CheckAccessCore the created WindowsPrincipal principal seems to be empty / anonymous, at least Name = "" and Type = Anonymous, although I have to enter my Windows credentials to run the service.

The config for the page itself allows anonymous access for various (partly historical) reasons.

In the web.config, I restrict access through different “location” sections as you can see below.

I have tried to shut of anonymous access, but then I get an error:

System.ServiceModel.ServiceActivationException

Since I do not want to lose anonymous access, I did not dig further yet ...

Does someone know how to get this working?

And: if something else in my code is bogus (except for my spelling), please tell me :-)

Interface:

namespace ZES
{
    [ServiceContract(Namespace = "ZESDataService")]
    public interface IZESData
    {
        [OperationContract]
        [WebGet]
        string Hallo();

        [OperationContract]
        [WebInvoke(Method = "POST",RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json, BodyStyle= WebMessageBodyStyle.WrappedRequest)]
        String SetBoxPosition(PostBoxData postBoxData);
    }
    [DataContract]
    public class PostBoxData
    {
        [DataMember] public int BoxID { get; set; }
        [DataMember] public char Bundesland { get; set; }
        [DataMember] public Decimal Latitude { get; set; }
        [DataMember] public Decimal Longtitude { get; set; }
    }
}

ZESData.svc:

<%@ ServiceHost Language="C#" Debug="true" Service="ZES.ZESData" CodeBehind="ZESData.svc.cs" %>

ZESData.svc.cs

namespace ZES
{
    [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
    public partial class ZESData : IZESData
    {
        public string Hallo()
        {
            //Simple func 4 testing
            return "Hallo Welt";
        }
        public String SetBoxPosition(PostBoxData postBoxData)
        {
            //function used 4 writing Data to Database
            return SetBoxPos(postBoxData.BoxID, postBoxData.Bundesland, postBoxData.Latitude, postBoxData.Longtitude);
        }
    }
}

web.config

<configuration>
  <appSettings/>
  <system.web>
    <compilation debug="true" targetFramework="4.0">
    </compilation>
    <authentication mode="Windows"/>
    <customErrors mode="Off"/>
  </system.web>
  <system.webServer>
    <validation validateIntegratedModeConfiguration="false"/>
  </system.webServer>
  <system.serviceModel>
    <bindings>
      <webHttpBinding>
        <binding name="httpsWebBinding">
          <security mode="Transport">
            <transport clientCredentialType="None" proxyCredentialType="None" />
          </security>
        </binding>
        <binding name="httpWebBinding">
          <security mode="None">
            <transport clientCredentialType="None" proxyCredentialType="None" />
          </security>
        </binding>
      </webHttpBinding>
    </bindings>

    <diagnostics performanceCounters="Default" />

    <behaviors>   
      <serviceBehaviors>
        <behavior name="ZESDataServiceTypeBehaviors" >
          <serviceMetadata  httpGetEnabled="true" httpsGetEnabled="true"/>
          <serviceDebug includeExceptionDetailInFaults="true" />
          <!--<serviceAuthorization principalPermissionMode="UseWindowsGroups" />-->
          <!--<serviceAuthorization serviceAuthorizationManagerType=" ZES.MyServiceAuthorizationManager,  ZES" />-->
        </behavior>
      </serviceBehaviors>

      <endpointBehaviors>
        <behavior name="ZESDataAspNetAjaxBehavior">
          <webHttp />
          <enableWebScript />
        </behavior>
      </endpointBehaviors>
    </behaviors>

    <serviceHostingEnvironment aspNetCompatibilityEnabled="true"
         multipleSiteBindingsEnabled="true" />

    <services>
      <service behaviorConfiguration="ZESDataServiceTypeBehaviors"
                name="ZES.ZESData">
        <endpoint address=""
                                    behaviorConfiguration="ZESDataAspNetAjaxBehavior"
                                    binding="webHttpBinding"
                                    bindingConfiguration="httpsWebBinding"
                                    name="ZESData"
                                    contract=" ZES.IZESData" />
        <endpoint address=""
                  behaviorConfiguration="ZESDataAspNetAjaxBehavior"
                  binding="webHttpBinding"
                  bindingConfiguration="httpWebBinding"
                  name="ZESData"
                  contract="ZES.IZESData" />
        <endpoint address="mex"
                                    binding="mexHttpsBinding"                                   name="mex"                                  contract="IMetadataExchange" />
      </service>
    </services>
  </system.serviceModel>

  <location>
    <system.web>
      <authorization>
        <allow roles="ZES_r"/>
        <allow roles="ZES_rw"/>
        <deny users="*"/>
      </authorization>
    </system.web>
  </location>
  <location path="Error">
    <system.web>
      <authorization>
        <allow users="?"/>
      </authorization>
    </system.web>
  </location>
  <location path="Default.aspx">
    <system.web>
      <authorization>
        <allow roles="ZES_r"/>
        <allow roles="ZES_rw"/>
        <deny users="*"/>
      </authorization>
    </system.web>
  </location>
  <location path="Images">
    <system.web>
      <authorization>
        <allow users="*"/>
      </authorization>
    </system.web>
  </location>
</configuration>

Solution

  • Again i found the answer myself ... Asking here helps finding the solution, with help from others AND without :-) But perhaps it may help someone else ...

    Like mentioned in the question, i did not try deaktivating anonymous Access because i got other Errors.

    Trying to resolve this error brought the answer.

    My Bindings were wrong: (left the old ones as comments for clerance)

    <bindings>
      <webHttpBinding>
        <binding name="httpsWebBinding">
          <security mode="Transport">
            <!-- <transport clientCredentialType="None" proxyCredentialType="None" /> -->
            <transport clientCredentialType="Windows" proxyCredentialType="Windows" />
          </security>
        </binding>
        <binding name="httpWebBinding">
          <security mode="None">
            <!-- <transport clientCredentialType="None" proxyCredentialType="None" /> -->
            <transport clientCredentialType="Windows" proxyCredentialType="Windows" />
          </security>
        </binding>
      </webHttpBinding>
    </bindings> 
    

    Now

        [PrincipalPermission(SecurityAction.Demand, Role = "rdm-WEB-Reas_rw")]
        public String SetBoxPosition(PostBoxData postBoxData)
    

    works nearly as expected, just that i get "accepted" instead of "Not Allowed" or simmilar, when using a user without the permission to write.

    I copied the bindings from a example for enabling https on your site, and thats what comes from copy and paste code from the net, that you do not fully understand :-)

    Thanks for reading and if you liked my answer please vote me up. I would realy like to be able to comment :-)