I'm having some difficulty setting up a WCF service to run under Windows authentication. The service is only consumed via jQuery using ajax.
IIS (version 6 on server 2003) is set to only allow Windows Authentication.
web.config has the <authentication mode="Windows" /> tag.
Here's the service section of the web.config:
<system.serviceModel>
<behaviors>
<endpointBehaviors>
<behavior name="AspNetAjaxBehavior">
<webHttp />
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior name="ServiceBehavior">
<serviceMetadata httpGetEnabled="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>
<services>
<service name="SearchService" behaviorConfiguration="ServiceBehavior">
<endpoint address="http://localhost:9534/SearchService.svc" behaviorConfiguration="AspNetAjaxBehavior"
binding="webHttpBinding" bindingConfiguration="webWinBinding"
name="searchServiceEndpoint" contract="MyApp.Services.ISearchService">
</endpoint>
</service>
</services>
<bindings>
<webHttpBinding>
<binding name="webWinBinding" maxBufferSize="2147483647" maxReceivedMessageSize="2147483647">
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Windows"/>
</security>
<readerQuotas maxArrayLength="100000" maxStringContentLength="2147483647" />
</binding>
</webHttpBinding>
</bindings>
The interface looks like this:
[ServiceContract(Namespace = "http://MyService.ServiceContracts/2012/02", Name = "SearchService")]
public interface ISearchService
{
[WebGet(ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Bare, UriTemplate = "GetSomeData?filter={filter}")]
[OperationContractAttribute(Action = "GetSomeData")]
string GetSomeData(string filter);
}
And the implementation:
[ServiceBehavior(IncludeExceptionDetailInFaults = true)]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
public class SearchService : ISearchService
{
public string GetSomeData(string filter)
{
// Call Database and get some results
// return the results
return "";
}
}
When I navigate to the service in Internet Explorer, it prompts me for my username and password, despite having Windows Authentication turned on.
As soon as I enable Anonymous Authentication, the service loads just fine and everything works. Problem is, I have other things going on in the web application that require anonymous to be turned off.
I've scoured the web and can't find anything on this problem.
Related
I'm trying to create a callback in WCF service. Service so far was using basicHttpBinding, so I want to add another end point for netTcpBinding. Service is already hosted in IIS. First It was hosted in IIS 6, but then I installed IIS 7.
So, I'm getting the following error:
The requested service, 'net.tcp://localhost:1801/MyServiceName.svc/NetTcpExampleAddress' could not be activated. See the server's diagnostic trace logs for more information.
When seeing the log, this is the message:
So the main error is:
Contract requires Duplex, but Binding 'BasicHttpBinding' doesn't support it or isn't configured properly to support it.
Here are my config files:
My Web.config for the server:
<system.serviceModel>
<bindings>
<netTcpBinding>
<binding name="demoServiceNetTcpBinding">
<security mode="None"/>
</binding>
</netTcpBinding>
<basicHttpBinding>
<binding name="demoServiceHttpBinding" receiveTimeout="00:05:00" sendTimeout="00:05:00" maxReceivedMessageSize="2147483647">
<security mode="None"/>
</binding>
</basicHttpBinding>
</bindings>
<services>
<service name="MyServerName.MyServiceName">
<host>
<baseAddresses>
<add baseAddress="net.tcp://localhost:1801/MyServiceName.svc/"/>
<add baseAddress="http://localhost:1800/MyServiceName.svc/"/>
</baseAddresses>
</host>
<endpoint
address="NetTcpExampleAddress"
binding="netTcpBinding"
bindingConfiguration="demoServiceNetTcpBinding"
contract="MyServerName.SharedContract.IMyServiceName"/>
<endpoint
address="BasicHttpExampleAddress"
binding="basicHttpBinding"
bindingConfiguration="demoServiceHttpBinding"
contract="MyServerName.SharedContract.IMyServiceName"/>
<endpoint address="mex" binding="mexTcpBinding" contract="IMetadataExchange" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceDebug includeExceptionDetailInFaults="true"/>
<serviceMetadata httpGetEnabled="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
My App.config for the client:
<system.serviceModel>
<bindings>
<netTcpBinding>
<binding name="demoServiceNetTcpBinding">
<security mode="None"/>
</binding>
</netTcpBinding>
<basicHttpBinding>
<binding name="demoServiceHttpBinding" receiveTimeout="00:05:00" sendTimeout="00:05:00" maxReceivedMessageSize="2147483647">
<security mode="None"/>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint name="NetTcpExampleName"
address="net.tcp://localhost:1801/DicomQueryService.svc/NetTcpExampleAddress"
bindingConfiguration ="demoServiceNetTcpBinding"
contract="MyServerName.SharedContract.IMyServiceName"
binding="netTcpBinding" />
<endpoint name="BasicHttpExampleName"
address="http://localhost:1800/MyServiceName.svc/BasicHttpExampleAddress"
bindingConfiguration ="demoServiceHttpBinding"
contract="MyServerName.SharedContract.IMyServiceName"
binding="basicHttpBinding" />
</client>
</system.serviceModel>
Settings in my IIS:
If there are any other pieces of code that you need, please let me know and I'll update the question.
EDIT 1:
Here are more details from the code, of how I'm calling the service from the client (on client side):
public class MyCommandClass : IMyServiceCallback
{
public MyCommandClass()
{
var ctx = new InstanceContext(new MyCommandClass());
DuplexChannelFactory<MyServerName.SharedContract.IMyServiceName> channel = new DuplexChannelFactory<MyServerName.SharedContract.IMyServiceName>(ctx, "NetTcpExampleName");
MyServerName.SharedContract.IMyServiceName clientProxy = channel.CreateChannel();
clientProxy.MyFunction(); //debug point is comming here and then it throws the error
clientProxy.ProcessReport();
(clientProxy as IClientChannel).Close();
channel.Close();
}
public void Progress(int percentageCompleted)
{
Console.WriteLine(percentageCompleted.ToString() + " % completed");
}
}
where interfaces (on server side) are defined as:
[ServiceContract(CallbackContract = typeof(IMyServiceCallback))]
public interface IMyServiceName
{
[OperationContract]
void MyFunction();
[OperationContract(IsOneWay = true)]
void ProcessReport();
}
public interface IMyServiceCallback
{
[OperationContract(IsOneWay = true)]
void Progress(int percentageCompleted);
}
and service (on server side) is defined as:
public class MyServiceName: IMyServiceName
{
public void MyFunction()
{
//do something
}
public void ProcessReport()
{
//trigger the callback method
for (int i = 1; i <= 100; i++)
{
Thread.Sleep(100);
OperationContext.Current.GetCallbackChannel<IMyServiceCallback>().Progress(i);
}
}
}
My methods so far are just a demo. Once the error related to this question is fixed, then I'll start with developing the methods.
Your service contract requires duplex connection (you have ServiceCallback attribute). Therefore all endpoints that this service exposes must support duplex connection. Net.tcp does support it, but basicHttp does not, so you cannot use basicHttp with your service now.
<system.serviceModel>
<!--WCF Service-->
<services>
<service name="Service.RestServices">
<endpoint address=""
binding="basicHttpBinding"
bindingConfiguration="secureHttpBinding"
contract="Service.IRestServices"/>
<endpoint address="mex"
binding="mexHttpsBinding"
contract="Service.IRestServices" />
</service>
</services>
<!--WCF Binding-->
<bindings>
<basicHttpBinding>
<binding name="secureHttpBinding">
<security mode="Transport">
<transport clientCredentialType="None"/>
</security>
</binding>
</basicHttpBinding>
</bindings>
<!--WCF Behaviors-->
<behaviors>
<serviceBehaviors>
<behavior>
<!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
<serviceMetadata httpsGetEnabled="true"/>
<!-- To receive exception details in faults for debugging purposes, set the value below to true. Set to false before deployment to avoid disclosing exception information -->
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
</behaviors>
Is there anything else I want to consider in my Web.config file? Below is my service interface.
Service Interface(IRestServices)
[OperationContract]
[WebInvoke(ResponseFormat = WebMessageFormat.Json, RequestFormat = WebMessageFormat.Json, Method = "POST", UriTemplate = "Login", BodyStyle = WebMessageBodyStyle.Wrapped)]
When I am try to call using HTTPS then response I get is 404(Not Found), while using HTTP, I am getting response data properly.
How can I call my rest api web service(WCF) using HTTPS ?
We have to define factory in our WebService.svc file to support Https in WCF rest service
<%# ServiceHost Language="C#" Debug="true" Service="XcellenceIt.Plugin.Misc.NopRestApi.Service.RestServices" Factory="System.ServiceModel.Activation.WebServiceHostFactory" %>
I am using a CustomUserNamePasswordValidator for my WCF web service. However, i am trying to add a IsAlive operation, which should be able to be called from clients, even when not authenticated.
For example, i want to be able to do a check, if a service is online and accessible on startup, so i can notify the user on missing inet connection or a not available service (due to maintenance).
I have code for all this already in place. What i am missing is how i can access the operation without passing a username and password.
I could probably just add a second service which allows anon access, but i'd really prefer to use the existing service.
The Validator is implemented like this (i ommited the actual checking code):
public sealed class MyCredentialValidator : UserNamePasswordValidator
{
public MyCredentialValidator ()
{
}
public override void Validate(string userName, string password)
{
Debug.WriteLine("MyCredentialValidator : Validate called.");
// do some checks
var isValid = CheckCredentials(userName, password)
if(!isValid)
{
throw new FaultException(...);
}
}
}
It is registered in the web.config like so:
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="SecureBehavior">
<serviceMetadata httpsGetEnabled="false"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
<serviceCredentials>
<userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="MyCredentialValidator,..."/>
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true"/>
<bindings>
<wsHttpBinding>
<binding name="SecureBinding" closeTimeout="00:10:00" openTimeout="00:10:00" receiveTimeout="00:10:00" sendTimeout="00:10:00" maxReceivedMessageSize="2147483647">
<security mode="TransportWithMessageCredential">
<message clientCredentialType="UserName"/>
</security>
<readerQuotas maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxStringContentLength="2147483647"/>
</binding>
</wsHttpBinding>
</bindings>
<services>
<service name="my service" behaviorConfiguration="SecureBehavior">
<endpoint address="" binding="wsHttpBinding" contract="my contract" bindingConfiguration="SecureBinding">
<identity>
<dns value="localhost"/>
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpsBinding" contract="IMetadataExchange"/>
</service>
</services>
</system.serviceModel>
client side configuration:
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="SecureBinding"
closeTimeout="00:10:00"
openTimeout="00:10:00"
receiveTimeout="00:10:00"
sendTimeout="00:10:00"
maxReceivedMessageSize="2147483647">
<security mode="TransportWithMessageCredential">
<message clientCredentialType="UserName"/>
</security>
<readerQuotas maxArrayLength="2147483647"
maxBytesPerRead="2147483647"
maxStringContentLength="2147483647"/>
</binding>
</wsHttpBinding>
</bindings>
<client>
<endpoint address="https://my service url"
contract="my contract"
binding="wsHttpBinding"
bindingConfiguration="SecureBinding"
name="secure" />
</client>
</system.serviceModel>
client side wcf call code:
var cf = new ChannelFactory<my contract>("secure");
using (IClientChannel channel = (IClientChannel)cf.CreateChannel())
{
channel.OperationTimeout = TimeSpan.FromSeconds(3);
bool success = false;
try
{
channel.Open();
result = ((my contract)channel).IsAlive();
channel.Close();
success = true;
}
finally
{
if (!success)
{
channel.Abort();
}
}
}
I have done something like this before,
depending on how you have integrated your custom validator in the wcf pipleline,
you could simply before you do the actual validation, which I guess returns something like true or false, you could check the incoming url or address and see if it is going to be going to your IsAlive operation, if that is the case, you could simply do a early return true.
Wcf has a few ways with which you can check what operation the client has called.
to be more accurate, I would need to know how you wrote your custom validator and where in the pipeline it integrates.
I'm struggling with the following scenario (here is the big picture):
I have a WCF Silverlight-enabled service (based on the DomainService class) into my Web project. The service is designed to be called by the Silverlight 5 clients and also by non-Silverlight consumers.
The service displays the WSDL info at the address
"http://localhost/mywebapproot/Services/MailService.svc" and therefore it can
be discovered and implemented by any client within the Web
project (which is fine).
Here are the symptoms:
The service can't be called by any
Silverlight client (here is the problem!) The error returned is "The remote server returned an exception: Not Found". If I change the name of the
service in Web.Config (let's say I change
MyCompany.Web.Services.MailService into MailService), the service can
now be called by any Silverlight client but at that time the service
is no longer discoverable.
I put includeExceptionDetailInFaults at True and tried to inspect the service with Fiddler/HTTPDebuggerPro but they didn't give me any detailed information about the exception. It looks to me that the Silverlight clients, in this configuration and for some reason, aren't able to create the .SVC file on the fly.
Here is the implementation:
MailService.svc implementation
<%# ServiceHost Language="C#" Debug="true" Service="MyCompany.Web.Services.MailService" CodeBehind="MailService.svc.cs" %>
MailService.svc.cs implementation
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public sealed partial class MailService : DomainService, IMailService
{
}
IMailService interface
[ServiceContract(ConfigurationName = "MyCompany.Web.Services.IMailService")]
public interface IMailService
{
//Some public methods flagged as [OperationContract] go here
}
Web.Config implementation
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="Secure_Behavior_Configuration">
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<basicHttpBinding>
<binding name="Public_MailService_BasicHttpBinding" transferMode="Streamed"
maxBufferSize="2147483647"
maxReceivedMessageSize="2147483647"
maxBufferPoolSize="2147483647">
<readerQuotas maxArrayLength="21400000" maxStringContentLength="21400000" maxBytesPerRead="21400000"/>
<security mode="None"/>
</binding>
</basicHttpBinding>
<services>
<service name="MyCompany.Web.Services.MailService" behaviorConfiguration="Secure_Behavior_Configuration">
<endpoint
address=""
binding="basicHttpBinding"
bindingConfiguration="Public_MailService_BasicHttpBinding"
contract="MyCompany.Web.Services.IMailService" />
<endpoint
address=""
binding="basicHttpBinding"
bindingConfiguration="Secure_MailService_BasicHttpBinding"
contract="MyCompany.Web.Services.IMailService" />
<endpoint contract="IMetadataExchange" binding="mexHttpBinding" address="mex" />
</service>
</services>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
</system.serviceModel>
Thanks a lot for any help!
Chris.
I want to secure some endpoint of a WCF service, i dont know if you can secure some endpoint and some not. Below I have the stripped WCF service (self hosted). The same WCF serves also the CA Policy file. If I secure this WCF service or some endpoints of ut the CA Policy part must not ask me a username password. The policy file must be accessible all the time. Is that also possible?
I found alot WCF custom blogs/postings. There are alot of ways to do security. All I want is that I can secure some endpoints with username/password but the credentials must not be visible with tools like Fiddler. The data however it can be visible in this case.
I implemented already a Customvalidator but the app.config file is also importent to define things. And I am not very good at that.
namespace WindowsFormsApplication11
{
public partial class Form1 : Form
{
public ServiceHost _host = null;
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
// Create a ServiceHost for the CalculatorService type and
// provide the base address.
_host = new ServiceHost(typeof(WmsStatService));
_host.AddServiceEndpoint(typeof(IPolicyProvider), new WebHttpBinding(), "").Behaviors.Add(new WebHttpBehavior());
_host.Open();
}
}
// Define a service contract.
[ServiceContract(Namespace = "http://WindowsFormsApplication11")]
public interface IWmsStat
{
[OperationContract]
string getConnectedViewers(string channelName);
[OperationContract]
string sayHello(string name);
}
[ServiceContract]
public interface IPolicyProvider
{
[OperationContract, WebGet(UriTemplate = "/ClientAccessPolicy.xml")]
Stream ProvidePolicy();
}
//[DataContract]
public class Ads
{
// [DataMember]
public string AdFileName { get; set; }
//[DataMember]
public string AdDestenationUrl { get; set; }
public string ConnectedUserIP { get; set; }
}
//
public class CustomValidator : UserNamePasswordValidator
{
public override void Validate(string userName, string password)
{
if(null == userName || null == password)
{
throw new ArgumentNullException();
}
if(userName == "Oguz" && password == "2009")
{
return;
}
FaultCode fc = new FaultCode("ValidationFailed");
FaultReason fr = new FaultReason("Good reason");
throw new FaultException(fr,fc);
}
}
//
public class WmsStatService : IWmsStat, IPolicyProvider
{
public string sayHello(string name)
{
return "hello there " + name + " nice to meet you!";
}
public Stream ProvidePolicy()
{
WebOperationContext.Current.OutgoingResponse.ContentType = "application/xml";
return new MemoryStream(File.ReadAllBytes("ClientAccessPolicy.xml"), false);
}
public string getConnectedViewers(string channelname)
{
// do stuff
return null;
}
}
}
The app.config. This config file does not work. I wanted to put the custom authentication for a endpoint. I have no clue.
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<services>
<service name="WindowsFormsApplication11.WmsStatService" behaviorConfiguration="mex">
<host>
<baseAddresses>
<add baseAddress="http://192.168.0.199:87" />
</baseAddresses>
</host>
<endpoint address="http://192.168.0.199:87/Test" binding="basicHttpBinding" bindingConfiguration="" contract="WindowsFormsApplication11.IWmsStat" behaviorConfiguration="MyServiceBehavior" />
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
</service>
</services>
<!--<bindings>
<wsHttpBinding>
<binding name="wshttp">
<security mode="Message">
<message clientCredentialType="UserName" />
</security>
</binding>
</wsHttpBinding>
</bindings>-->
<behaviors>
<serviceBehaviors>
<behavior name="mex">
<serviceMetadata httpGetEnabled="true" httpGetUrl=""/>
</behavior>
<behavior name="MyServiceBehavior">
<serviceCredentials>
<userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="WindowsFormsApplication11.CustomValidator, CustomValidator" />
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
I want to secure some endpoint of a
WCF service, i dont know if you can
secure some endpoint and some not.
Sure - you just need to create two separate binding configurations, and use one on those endpoints that are secured, the other on the others:
<bindings>
<basicHttpBinding>
<binding name="secured">
<security mode="Message">
<message ...... />
</security>
</binding>
<binding name="unsecured">
<security mode="None" />
</binding>
</basicHttpBinding>
</bindings>
<services>
<service name="WindowsFormsApplication11.WmsStatService" behaviorConfiguration="mex">
<host>
<baseAddresses>
<add baseAddress="http://192.168.0.199:87" />
</baseAddresses>
</host>
<endpoint address="/Secured/Test"
binding="basicHttpBinding" bindingConfiguration="secured"
contract="WindowsFormsApplication11.IWmsStat"
behaviorConfiguration="MyServiceBehavior" />
<endpoint address="/Unsecured/Test"
binding="basicHttpBinding" bindingConfiguration="unsecured"
contract="WindowsFormsApplication11.IWmsStat"
behaviorConfiguration="MyServiceBehavior" />
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
</service>
</services>
Marc
PS: not sure if that's just a problem with your postings not being up to date anymore - have you noticed, that you have two separate behavior configurations:
<behaviors>
<serviceBehaviors>
<behavior name="mex">
<serviceMetadata httpGetEnabled="true" httpGetUrl=""/>
</behavior>
<behavior name="MyServiceBehavior">
<serviceCredentials>
<userNameAuthentication
userNamePasswordValidationMode="Custom"
customUserNamePasswordValidatorType="WindowsFormsApplication11.CustomValidator, CustomValidator" />
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
and your service is only referencing the "mex" behavior? That means, your service is indeed using the <serviceMetadata> behavior - but NOT the <serviceCredentials> one!
You need to merge these into one and then reference just that:
<behaviors>
<serviceBehaviors>
<behavior name="Default">
<serviceMetadata httpGetEnabled="true" httpGetUrl=""/>
<serviceCredentials>
<userNameAuthentication
userNamePasswordValidationMode="Custom"
customUserNamePasswordValidatorType="WindowsFormsApplication11.CustomValidator, CustomValidator" />
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service name="...." behaviorConfiguration="Default"
Marc
If you want to protect entire message, Transport security mode is a way to go. If you want to only your headers to be encrypted/signed, Message security mode allows this, but you'll have to use wsHttpBinding. You may also consider using Digest to protect credentials.
As for your example, I think your commented part should look like this:
<bindings>
<basicHttpBinding>
<binding name="secure">
<security mode="Transport">
<transport clientCredentialType="Basic" />
</security>
</binding>
</basicHttpBinding>
</bindings>
You'll also have to update your endpoint declaration:
<endpoint
address="https://192.168.0.199:87/Test"
binding="basicHttpBinding" bindingConfiguration="secure"
contract="WindowsFormsApplication11.IWmsStat" />
You won't be allowed to use plain HTTP with transport security mode.