WCF service not show metadata on server (return 404), only locally it works - wcf

I have a problem with metadata (wsdl on service soap).
Locally everything works fine. and at the address https: // localhost / DataImportSoapService /? wsdl the wsdl is exposed.
Nothing is shown on the server. Return 404.
I state that I have other active services in WCF and that the other .svc are correctly exposed.
While this basicHttpBinding service with basic auth doesn't work.
So on the server I activated everything:
My web.config
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="DatineoUser" value="zzzzzz" />
<add key="DatineoPass" value="xxxx" />
<add key="UrlServiceNewEra" value="https://xxxxx/common/importDataCarrier?satcode=datineo" />
</appSettings>
<system.web>
<compilation debug="true" />
</system.web>
<!-- When deploying the service library project, the content of the config file must be added to the host's
app.config file. System.Configuration does not support config files for libraries. -->
<system.serviceModel>
<services>
<service behaviorConfiguration="MetadataBehavior" name="TA_service_library_BA.DataImportSoapService">
<endpoint address="datineoV1" binding="basicHttpBinding"
bindingConfiguration="wsHttpBinding_LargeBinding" name="EndpointAVeryBigSum_BasicAuthentication"
contract="TA_service_library_BA.IDataImportSoapService" />
<endpoint address="mex"
binding="mexHttpsBinding"
contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="https://localhost/DataImportSoapService/" />
</baseAddresses>
</host>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="MetadataBehavior">
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
<serviceCredentials>
<userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="TA_service_library_BA.ServiceAuthenticator, TA_service_library_BA"/>
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<basicHttpBinding>
<binding name="wsHttpBinding_LargeBinding" closeTimeout="00:05:00" openTimeout="00:05:00" receiveTimeout="00:15:00" sendTimeout="00:15:00" maxBufferSize="15728640" maxBufferPoolSize="15728640" maxReceivedMessageSize="15728640">
<readerQuotas maxDepth="2000000" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647"/>
<security mode="TransportWithMessageCredential">
<message clientCredentialType="UserName"/>
</security>
</binding>
</basicHttpBinding>
</bindings>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true"/>
</system.serviceModel>
</configuration>
My classes:
namespace TA_service_library_BA
{
public class ServiceAuthenticator : UserNamePasswordValidator
{
public override void Validate(string userName, string password)
{
if (string.IsNullOrEmpty(userName) || string.IsNullOrEmpty(password))
throw new SecurityTokenException("Username and password required");
if (!(userName == ConfigurationManager.AppSettings["DatineoUser"] && password == ConfigurationManager.AppSettings["DatineoPass"]))
throw new FaultException(string.Format("Wrong username ({0}) or password ", userName));
}
}
}
namespace TA_service_library_BA
{
// NOTA: è possibile utilizzare il comando "Rinomina" del menu "Refactoring" per modificare il nome di interfaccia "IDataImportService" nel codice e nel file di configurazione contemporaneamente.
[ServiceContract(Namespace = "http://sen.company.com")]
[XmlSerializerFormat]
public interface IDataImportSoapService
{
[OperationContract]
[WebInvoke(Method = "POST", BodyStyle = WebMessageBodyStyle.Bare)]
PushResponse PushDataArray(PushData pushDataArray);
//++++++++++++++++++++++++++++++++++++++++++++++
}
}
namespace TA_service_library_BA
{
// NOTE: You can use the "Rename" command on the "Refactor" menu to change the class name "Service1" in both code and config file together.
public class DataImportSoapService : IDataImportSoapService
{
public PushResponse PushDataArray(PushData pushDataArray)
{
PushResponse responsePush = new PushResponse();
try
{
string authkey = ConfigurationManager.AppSettings["DatineoUser"] + ":" + ConfigurationManager.AppSettings["DatineoPass"];
string encAuthkey = CommFun.Base64Encode(authkey);
WebRequest request = WebRequest.Create(ConfigurationManager.AppSettings["UrlServiceNewEra"]);
request.ContentType = "application/json";
request.Method = "POST";
request.Headers.Add("Authorization", "Basic " + encAuthkey);
using (var streamWriter = new StreamWriter(request.GetRequestStream()))
{
string json = new JavaScriptSerializer().Serialize(pushDataArray);
streamWriter.Write(json);
}
var response = (HttpWebResponse)request.GetResponse();
var responseString = new StreamReader(response.GetResponseStream()).ReadToEnd();
if (response.StatusCode.Equals(HttpStatusCode.OK) || response.StatusCode.Equals(HttpStatusCode.NoContent))
{
//istanzio la risposta contenitore
responsePush.success = true;
responsePush.message = responseString;
}
else
{
//istanzio la risposta contenitore
responsePush.success = false;
responsePush.message = responseString;
}
}
catch (Exception ex)
{
//istanzio la risposta contenitore
responsePush.success = false;
responsePush.message = ex.Message;
}
return responsePush;
}
}
}
Why do some projects expose at least the .svc while this last service gives me 404 to the .svc file?
Beyond this then I don't understand what the hell is wrong with the configuration ... with IIS express everything goes .. on the server no.
Thanks for your help. I've been banging my head for a week and a half. I have tried the impossible. Tnx

You can check the following conditions:
Whether the permission of the managed directory is granted.
Whether the.NET version matches.
Is there a valid certificate on the site.
Try to put the image in the same path and find it.

Related

Test program just wont invoke service, yet everything looks okay - getting 404 not found

I've created a WCF service to receive data from a sending application. When run, the usual index listing appears:
and clicking on the .svc shows the success page:
So, I've created a basic test form to invoke the methods of the service (there are 2, both are "POST" methods). Since the service methods use JSON & webhttp, I am attempting to invoke the service via an HttpWebRequest.
private void button1_Click(object sender, EventArgs e) {
try {
var request = (HttpWebRequest)WebRequest.Create("http://localhost:54945/Take2ToOffice.svc/ErrorReport");
request.ContentType = "'text/json; charset=utf-8'";
request.Method = "POST";
byte[] chunk = new byte[2048]; //chunk gets initialised, but what it
//contains is mostly irrelevant here
string result = "";
ErrorInfo EI = new ErrorInfo {
Edumis = "9999",
SiteName = "Unknown",
ErrorID = "123",
ContentBlock = chunk
};
string json = new JavaScriptSerializer().Serialize(EI);
//MessageBox.Show(json);
using (var sW = new StreamWriter(request.GetRequestStream())) {
sW.Write(json);
sW.Flush();
sW.Close();
}
var response = (HttpWebResponse)request.GetResponse();
using (var streamReader = new StreamReader(response.GetResponseStream())) {
result = streamReader.ReadToEnd();
}
MessageBox.Show(result);
}
catch (WebException wex) {
string lcResult;
if (wex.Response != null) {
lcResult = "ERROR (web exception, response generated): " + Environment.NewLine;
StreamReader sr = new StreamReader(wex.Response.GetResponseStream());
lcResult += sr.ReadToEnd();
}
else {
lcResult = "ERROR (web exception, NO RESPONSE): " + wex.Message + wex.StackTrace;
}
MessageBox.Show(lcResult);
}
catch (Exception ex) {
MessageBox.Show(ex.Message);
}
}
It all seems like pretty basic stuff - especially since I wrote another service very similar to this a few years ago, and my starting point for everything I've done now, was the code I wrote previously - and at this point, I'm just doing this in my development environment.
Yet,
var response = (HttpWebResponse)request.GetResponse();
Returns 404 Not Found. The WebException.Response contains:
{System.Net.HttpWebResponse}
[System.Net.HttpWebResponse]: {System.Net.HttpWebResponse}
base: {System.Net.HttpWebResponse}
ContentLength: 0
ContentType: ""
Headers: {X-SourceFiles: =?UTF-8?B?QzpcVXNlcnNcVXNlclxEb2N1bWVudHNcVmlzdWFsIFN0dWRpb1xWaXN1YWwgU3R1ZGlvIDIwMTNcUHJvamVjdHNcVGFrZTJPZmZpY2VDb21tdW5pY2F0aW9uc1xUYWtlMk9mZmljZUNvbW11bmljYXRpb25zXFRha2UyVG9PZmZpY2Uuc3ZjXEVycm9yUmVwb3J0?=
Content-Length: 0
Cache-Control: private
Date: Thu, 27 Apr 2017 03:19:29 GMT
Server: Microsoft-IIS/8.0
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
}
IsFromCache: false
IsMutuallyAuthenticated: false
ResponseUri: {http://localhost:54945/Take2ToOffice.svc/ErrorReport}
SupportsHeaders: true
But there is no actual response at all (length = 0). If I put a breakpoint in the service, (and start both the test form, and the service - separate projects in the same solution), the breakpoint is never hit.
Logically it looks like the service isn't running, or for some reason can't be found - but the listing and success page are readily seen in a browser, and at the address (localhost:54945) shown in the program.
Can anyone explain what's going on, or maybe what's going wrong? Please help, I'm totally stumped.
The web.config is as follows:
<?xml version="1.0"?>
<configuration>
<connectionStrings>
...
</connectionStrings>
<appSettings>
...
</appSettings>
<system.web>
<compilation debug="true" targetFramework="4.5"/>
<httpRuntime/>
</system.web>
<system.serviceModel>
<services>
<service name="Take2OfficeCommunications.Take2ToOffice" behaviorConfiguration="serviceBehavior">
<endpoint address="rest"
binding="webHttpBinding"
bindingConfiguration="WebBinding"
behaviorConfiguration="web"
name="restEndpoint"
contract="Take2OfficeCommunications.ITake2ToOffice"/>
<endpoint contract="IMetadataExchange" binding="mexHttpBinding" address="mex"/>
</service>
</services>
<bindings>
<webHttpBinding>
<binding name="WebBinding" maxBufferPoolSize="2147483647" maxReceivedMessageSize="2147483647">
<security mode="Transport" />
<readerQuotas maxDepth="32" maxStringContentLength="2147483647" maxArrayLength="16384" maxBytesPerRead="4096" maxNameTableCharCount="16384"/>
</binding>
</webHttpBinding>
</bindings>
<behaviors>
<endpointBehaviors>
<behavior name="web">
<webHttp helpEnabled="true" />
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior name="serviceBehavior">
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true"/>
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
<directoryBrowse enabled="true"/>
</system.webServer>
</configuration>
Thanks for looking, and for any comments you can make.

wcf rest service consumption in c# console application

I made wcf rest service by going New->projects->WCF Service Application
I am unable to use methods in console application while i have hosted wcf rest service and referenced wcf rest service in application
My Application code is below :
IRestServiceImpL
[ServiceContract]
public interface IRestServiceImpL
{
[OperationContract]
[WebInvoke(Method = "GET", ResponseFormat = WebMessageFormat.Xml,
RequestFormat = WebMessageFormat.Xml, UriTemplate = "XmlData/{id}")]
string XmlData(string id);
[OperationContract]
[WebInvoke(Method = "GET", ResponseFormat = WebMessageFormat.Json,
RequestFormat = WebMessageFormat.Json, UriTemplate = "JsonData/{id}")]
string JsonData(string id);
}
RestServiceImpL.svc.cs
[AspNetCompatibilityRequirements(RequirementsMode
= AspNetCompatibilityRequirementsMode.Allowed)]
public class RestServiceImpL : IRestServiceImpL
{
public string XmlData(string id)
{
return "you requested for " + id;
}
public string JsonData(string id)
{
return "you requested for " + id;
}
}
Config File
<system.web>
<compilation debug="true" targetFramework="4.0" />
</system.web>
<system.serviceModel>
<bindings>
<webHttpBinding>
<binding name="StreamedRequestWebBinding"
bypassProxyOnLocal="true"
useDefaultWebProxy="false"
hostNameComparisonMode="WeakWildcard"
sendTimeout="10:15:00"
openTimeout="10:15:00"
receiveTimeout="10:15:00"
maxReceivedMessageSize="2147483647"
maxBufferSize="2147483647"
maxBufferPoolSize="2147483647"
transferMode="StreamedRequest"
crossDomainScriptAccessEnabled="true"
>
<readerQuotas maxArrayLength="2147483647"
maxStringContentLength="2147483647" />
</binding>
</webHttpBinding>
</bindings>
<services>
<service name="RestService.RestServiceImpL" behaviorConfiguration="ServiceBehaviour">
<!--<endpoint address="" binding="basicHttpBinding" contract="RestService.IRestServiceImpL"></endpoint>-->
<endpoint address="" binding="webHttpBinding" name="StreamedRequestWebBinding" bindingConfiguration="StreamedRequestWebBinding" contract="RestService.IRestServiceImpL" behaviorConfiguration="web"></endpoint>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="ServiceBehaviour">
<!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
<serviceMetadata httpGetEnabled="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>
<endpointBehaviors>
<behavior name="web">
<webHttp/>
</behavior>
</endpointBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" aspNetCompatibilityEnabled="true" />
</system.serviceModel>
<system.webServer>
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="*"/>
</customHeaders>
</httpProtocol>
<modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>
I host this service application in IIS
Now after giving reference to console application when i call its methods
by using proxy class then i got error of Invalid Operation Contract Exception
that endpoint not specified
calling code is below :
ServiceClient oServiceClient = new ServiceClient();<br/>
oServiceClient.JsonData("123");
Please suggest what is problem in the code.
Thanks stack overflow for support...I did it..
The calling Wcf Rest Service code is written below :
//code for xml Response consumption from WCF rest Service[Start]
WebRequest req = WebRequest.Create(#"http://RestService.com/WcfRestService/RestServiceImpL.svc/XmlData/sad");
req.Method = "GET";
req.ContentType = #"application/xml; charset=utf-8";
HttpWebResponse resp = req.GetResponse() as HttpWebResponse;
if (resp.StatusCode == HttpStatusCode.OK)
{
XmlDocument myXMLDocument = new XmlDocument();
XmlReader myXMLReader = new XmlTextReader(resp.GetResponseStream());
myXMLDocument.Load(myXMLReader);
Console.WriteLine(myXMLDocument.InnerText);
}
//code for xml Response consumption from WCF rest Service[END]
//****************************************************************************
//code for json Response consumption from WCF rest Service[Start]
WebRequest req2 = WebRequest.Create(#"http://RestService.com/WcfRestService/RestServiceImpL.svc/JsonData/as");
req2.Method = "GET";
req2.ContentType = #"application/json; charset=utf-8";
HttpWebResponse response = (HttpWebResponse)req2.GetResponse();
string jsonResponse = string.Empty;
using (StreamReader sr = new StreamReader(response.GetResponseStream()))
{
jsonResponse = sr.ReadToEnd();
Console.WriteLine(jsonResponse);
}
//code for json Response consumption from WCF rest Service[END]

Inject an object into a custom WCF UserNamePassValidator - Autofac

I have a service which is hosted in IIS. It is configured by Web.config.
I have created a custom UserNamePassValidator which works if I I have the logic in the validate method. But I want the logic in another project and injected in using DI as below.
public class UserNamePassValidator : System.IdentityModel.Selectors.UserNamePasswordValidator
{
private readonly ISystemAuthentication _systemAuthentication;
public UserNamePassValidator(ISystemAuthentication systemAuthentication)
{
_systemAuthentication = systemAuthentication;
}
public override void Validate(string userName, string password)
{
_systemAuthentication.Validate(userName, password))
}
}
I am using the Autofac WCF integration.
var builder = new ContainerBuilder();
builder.RegisterType<AuthenticationService>().As<IAuthenticationService>();
builder.Register(c => new SystemAuthentication()).As<ISystemAuthentication>();
builder.Register(c => new UserNamePassValidator(c.Resolve<ISystemAuthentication>()));
AutofacHostFactory.Container = builder.Build();
When I browse to the service i receive the following error:
[MissingMethodException: No parameterless constructor defined for this object.]
web.config behaviour;
<userNameAuthentication
userNamePasswordValidationMode="Custom"
customUserNamePasswordValidatorType="MyNamespace.UserNamePassValidator, service" />
I have read the following related post but the example is a self hosted service:
How to inject an object into a WCF validator class
EDIT
<system.serviceModel>
<services>
<service behaviorConfiguration="Namespace.AuthenticationServiceBehaviour" name="Namespace.AuthenticationService" >
<endpoint address="" binding="wsHttpBinding" contract="Namespace.IAuthenticationService" bindingConfiguration="SafeServiceConf">
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="Namespace.AuthenticationServiceBehaviour">
<serviceMetadata httpGetEnabled="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="true" />
<serviceCredentials>
<serviceCertificate findValue="AuthenticationService"
storeLocation="LocalMachine"
storeName="My"
x509FindType="FindBySubjectName" />
<userNameAuthentication
userNamePasswordValidationMode="Custom"
customUserNamePasswordValidatorType="Namespace.UserNamePassValidator, Service" />
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<wsHttpBinding>
<binding name="SafeServiceConf" maxReceivedMessageSize="65536">
<readerQuotas maxStringContentLength="65536" maxArrayLength="65536" maxBytesPerRead="65536" />
<security mode="Message">
<message clientCredentialType="UserName" />
</security>
</binding>
</wsHttpBinding>
</bindings>
SystemAuthentication class
public class SystemAuthentication : ISystemAuthentication
{
public bool Validate(string userName, string password)
{
// removed code for abbreviation
return true;
}
WCF Authentication Service
public class AuthenticationService : IAuthenticationService
{
public bool Authenticate(string email, string password)
{
// removed for abbreviation
return true;
}
}
From the help of this post UserNamePasswordValidator: When DI and Framework collide
From the XML configuraiton i removed:
<userNameAuthentication
userNamePasswordValidationMode="Custom"
customUserNamePasswordValidatorType="MyNamespace.UserNamePassValidator, service" />
I added the behaviour to the AutoFacHostFactory service host
IContainer container = builder.Build();
AutofacHostFactory.Container = container;
AutofacHostFactory.HostConfigurationAction = host =>
{
var auth = host.Credentials.UserNameAuthentication;
auth.UserNamePasswordValidationMode = UserNamePasswordValidationMode.Custom;
auth.CustomUserNamePasswordValidator = container.Resolve<UserNamePassValidator>();
};
This works perfectly, but it would have been nicer to be able to do it from the web.config. If anyone knows a better way please post :)

WP7 + WCF + IIS + HTTPS (Transport) + Basic Authentication

I've read a lot of posts about the problem to use WP7 + WCF (IIS 7) over HTTPS with basic authentication but I'm still in trouble with it...
If I just use HTTPS transport without BasicAuth it works like a charm. But both combinated doesn't work for me...
Maybe you can help me to identify my failure...
My ClientConfig:
<configuration>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_IService1" maxBufferSize="2147483647"
maxReceivedMessageSize="2147483647">
<security mode="Transport" />
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint
binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IService1"
contract="ServiceReference1.IService1" name="BasicHttpBinding_IService1" />
</client>
</system.serviceModel>
My ServiceConfig:
<?xml version="1.0"?>
<configuration>
<appSettings/>
<system.web>
<compilation debug="true" targetFramework="4.0"/>
<pages controlRenderingCompatibilityVersion="3.5" clientIDMode="AutoID"/>
</system.web>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
<serviceCredentials>
<userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="WP7.CustomUserNameValidator, WP7" />
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
<bindings>
<basicHttpBinding>
<binding maxReceivedMessageSize="2147483647">
<readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" />
<security mode="TransportWithMessageCredential" >
<transport clientCredentialType="Basic"/>
<message clientCredentialType="UserName"/>
</security>
</binding>
</basicHttpBinding>
</bindings>
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>
</configuration>
My CustomUserNameValidator used in Service:
namespace WP7
{
public class CustomUserNameValidator : UserNamePasswordValidator
{
// This method validates users. It allows in two users,
// test1 and test2 with passwords 1tset and 2tset respectively.
// This code is for illustration purposes only and
// MUST NOT be used in a production environment because it
// is NOT secure.
public override void Validate(string userName, string password)
{
if (null == userName || null == password)
{
throw new ArgumentNullException();
}
if (!(userName == "test1" && password == "1tset") && !(userName == "test2" && password == "2tset"))
{
throw new FaultException("Unknown Username or Incorrect Password");
}
}
}
}
The code in my Wp7 App to call a method a sync (with a solution from: http://cisforcoder.wordpress.com/2010/12/01/how-to-implement-basic-http-authentication-in-wcf-on-windows-phone-7/#comment-174):
proxy = new ServiceReference1.Service1Client();
proxy.Endpoint.Address = new System.ServiceModel.EndpointAddress(new Uri(Details.mySettings.EndpointAddress));
proxy.PingServerCompleted += new EventHandler<ServiceReference1.PingServerCompletedEventArgs>(proxy_PingServerCompleted);
var credentials = EncodeBasicAuthenticationCredentials("test1", "1tset");
using (OperationContextScope scope =
new OperationContextScope(proxy.InnerChannel))
{
HttpRequestMessageProperty request = new HttpRequestMessageProperty();
request.Headers[System.Net.HttpRequestHeader.Authorization] = "Basic " + credentials;
OperationContext.Current.OutgoingMessageProperties.Add(
HttpRequestMessageProperty.Name, request);
proxy.PingServerAsync(myServer);
}
private string EncodeBasicAuthenticationCredentials(string username, string password)
{
//first concatenate the user name and password, separated with :
string credentials = username + ":" + password;
//Http uses ascii character encoding, WP7 doesn’t include
// support for ascii encoding but it is easy enough to convert
// since the first 128 characters of unicode are equivalent to ascii.
// Any characters over 128 can’t be expressed in ascii so are replaced
// by ?
var asciiCredentials = (from c in credentials
select c <= 0x7f ? (byte)c : (byte)'?').ToArray();
//finally Base64 encode the result
return Convert.ToBase64String(asciiCredentials);
}
Furthermore I've already set "Basic Authentication" setting in the IIS Virtual Directory to "Enabled".
Everytime I've got some different error exceptions:
either CommunicationException or SecurityException or what else...
Someone an idea which might be solve my problem?
Thanks.
Jason
The client needs to also specify the clientCredentialType - that's missing from the client config. So the client isn't expecting to have to send credentials but the service is expecting them

Securing WCF service endpoint with custom authentication

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.