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>
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 :-)