I am trying to use a ServiceReference in a C# project.
The project is intended to test a connection. I have a customer who is trying to connect with a C# application to one web service of one of my colleagues. The connection can't be established and he is assuming that it is our own mistake.
I am trying to write now a simple C# project.
Thats enough of story... now the Information needed.
The customer uses a Proxy server
I try to connect to this web service for testing reasons
http://www.w3schools.com/webservices/tempconvert.asmx
I Use .Net Framework 4.0
My Project compiles into a Windows Forms application.
Here The source code of my Method:
private void button2_Click(object sender, EventArgs e)
{
try
{
//Create Client
ServiceReference1.TempConvertSoapClient client = new ServiceReference1.TempConvertSoapClient(#"TempConvertSoap",#"http://www.w3schools.com/webservices/tempconvert.asmx");
if (client.ClientCredentials != null)
{
//Use Values which are typed in in the GUI
string user = tbUser.Text;
string password = tbPassword.Text;
string domain = tbDomain.Text;
//Check what information is used by the customer.
if (!string.IsNullOrEmpty(user) && !string.IsNullOrEmpty(password) && !string.IsNullOrEmpty(domain))
{
client.ClientCredentials.Windows.ClientCredential = new NetworkCredential(user, password, domain);
}
if (!string.IsNullOrEmpty(user) && !string.IsNullOrEmpty(password))
{
client.ClientCredentials.Windows.ClientCredential = new NetworkCredential(user, password);
}
}
//Oh nooo... no temperature typed in
if (string.IsNullOrEmpty(tbFahrenheit.Text))
{
//GOOD BYE
return;
}
//Use the webservice
string celsius = client.FahrenheitToCelsius(tbFahrenheit.Text); //<-- Simple Calculation
tbCelsius.Text = celsius;
}
catch(Exception ex)
{
//Something
MessageBox.Show(ex.ToString());
}
}
Here is my Question:
How can i set a proxy to this service reference or rather the client ?
There is no property or setter for this purpose. I tried it with the ClientCredentials
Okay i found the answer myself.
Hopefully it will help somebody ;).
This part creates a binding. This can later be used in the webservice
private void button2_Click(object sender, EventArgs e)
{
BasicHttpBinding binding = new BasicHttpBinding("TempConvertSoap");
if (!string.IsNullOrEmpty(tbProxy.Text))
{
binding.Security.Mode = BasicHttpSecurityMode.TransportCredentialOnly;
binding.Security.Transport.ProxyCredentialType = HttpProxyCredentialType.Basic;
string proxy = string.Format("http://{0}", tbProxy.Text);
if (!string.IsNullOrEmpty(tbPort.Text))
{
proxy = string.Format("{0}:{1}",proxy,tbPort.Text);
}
binding.UseDefaultWebProxy = false;
binding.ProxyAddress = new Uri(proxy);
}
EndpointAddress endpoint = new EndpointAddress(#"http://www.w3schools.com/webservices/tempconvert.asmx");
Here begins the old part where i set the binding .
try
{
//Create Client
ServiceReference1.TempConvertSoapClient client = new ServiceReference1.TempConvertSoapClient(binding, endpoint);
if (client.ClientCredentials != null)
{
//Use Values which are typed in in the GUI
string user = tbUser.Text;
string password = tbPassword.Text;
string domain = tbDomain.Text;
client.ClientCredentials.UserName.UserName = user;
client.ClientCredentials.UserName.Password = password;
client.ClientCredentials.Windows.ClientCredential.Domain = domain;
//Check what information is used by the customer.
if (!string.IsNullOrEmpty(user) && !string.IsNullOrEmpty(password) && !string.IsNullOrEmpty(domain))
{
client.ClientCredentials.Windows.ClientCredential = new NetworkCredential(user, password, domain);
}
if (!string.IsNullOrEmpty(user) && !string.IsNullOrEmpty(password))
{
client.ClientCredentials.Windows.ClientCredential = new NetworkCredential(user, password);
}
}
//Oh nooo... no temperature typed in
if (string.IsNullOrEmpty(tbFahrenheit.Text))
{
//GOOD BYE
return;
}
//Use the webservice
//THIS ONE IS IMPORTANT
System.Net.ServicePointManager.Expect100Continue = false;
string celsius = client.FahrenheitToCelsius(tbFahrenheit.Text); //<-- Simple Calculation
tbCelsius.Text = celsius;
}
catch(Exception ex)
{
//Something
tbCelsius.Text = ex.Message;
MessageBox.Show(ex.ToString());
}
}
I used Squid as my proxy and use a firewall besides the proxy.
After i configured it succesfully i encountered the error (417) Expectation failed.
During the research i found a line of code which helped me to "resolve" this problem
System.Net.ServicePointManager.Expect100Continue = false;
It's and old question but still relevant. The accepted answer works, but I managed to resolve this with a different approach. When you add service reference to your project, Visual Studio will add bindings and endpoint addresses etc to web.config/app.config (depending on the application type). You can add the proxy configuration (ip and port) directly to the config file so that you won't need to do anything special on the code side:
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="MyServiceBinding"
proxyAddress="http://123.123.12.1:80" useDefaultWebProxy="false" />
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://address.com/endpoint"
binding="basicHttpBinding" bindingConfiguration="MyServiceBinding"
contract="..." name="..." />
</client>
</system.serviceModel>
So change the ip and port to your proxy servers ip and port and remember to use useDefaultWebProxy="false" so that the application will use that proxy with this service reference.
Reference for basicHttpBinding.
Related
I am completely new to this Microsoft Dynamics AX 2012 tool and WCF service. I have a self hosted WCF service, where it takes AX 2012 service wsdl URL, AX server domain name, user name and password as inputs and will try to download metadata of this wsdl url without any user authentication mechanism in place.
MY AX 2012 service WSDl URL below:
http://####:8##1/DynamicsAx/Services/TestService?wsdl ---> WSDLEndpoint
I am dynamically creating WSHttpBinding, MetadataExchangeClient and assigned all it's properties and passed my wsdl endpoint.
Below is my sample code :
var binding = new WSHttpBinding(SecurityMode.None) { MaxReceivedMessageSize = int.MaxValue, MaxBufferPoolSize = int.MaxValue };
var mexClient = new MetadataExchangeClient(binding)
{
ResolveMetadataReferences = true,
MaximumResolvedReferences = int.MaxValue,
OperationTimeout = TimeSpan.FromSeconds(TimeOutInSeconds),
HttpCredentials =
new NetworkCredential(Username, Password, Domain)
};
mexClient.GetMetadata(new Uri(WSDLEndpoint), MetadataExchangeClientMode.HttpGet);
Log.Info("Metadata successfully downloaded.");
But above code won't bother about user credentials validation, it directly downloads metadata out of the WSDL URL, but I am looking to validate user credentials and after successful authentication, will download metadata.
Please help me with some authentication approach to introduce on top of wshttpbinding that supports cross platforms.
I don’t fully understand your meaning. Are you trying to create a WCF service with custom username/password authentication? This requires that we configure a certificate on the server-side. I created an example, wishing it is instrumental for you.
Server-side.
class Program
{
static void Main(string[] args)
{
Uri uri = new Uri("http://localhost:21011");
WSHttpBinding binding = new WSHttpBinding();
binding.Security.Mode = SecurityMode.Message;
binding.Security.Message.ClientCredentialType = MessageCredentialType.UserName;
using (ServiceHost sh = new ServiceHost(typeof(MyService), uri))
{
sh.AddServiceEndpoint(typeof(IService), binding, "");
ServiceMetadataBehavior smb;
smb = sh.Description.Behaviors.Find<ServiceMetadataBehavior>();
if (smb == null)
{
smb = new ServiceMetadataBehavior()
{
HttpGetEnabled = true
};
sh.Description.Behaviors.Add(smb);
}
sh.Credentials.ServiceCertificate.SetCertificate(StoreLocation.LocalMachine, StoreName.My, X509FindType.FindByThumbprint, "5ba5022f527e32ac02548fc5afc558de1d314cb6");
Binding mexbinding = MetadataExchangeBindings.CreateMexHttpBinding();
sh.AddServiceEndpoint(typeof(IMetadataExchange), mexbinding, "mex");
sh.Opened += delegate
{
Console.WriteLine("Service is ready");
};
sh.Closed += delegate
{
Console.WriteLine("Service is clsoed");
};
sh.Open();
Console.ReadLine();
//pause
sh.Close();
Console.ReadLine();
}
}
}
[ServiceContract]
public interface IService
{
[OperationContract]
string Test();
}
public class MyService : IService
{
public string Test()
{
return DateTime.Now.ToString();
}
}
On the Client-side, we create a client proxy by adding service reference.
ServiceReference1.ServiceClient client = new ServiceClient();
client.ClientCredentials.UserName.UserName = "administrator";
client.ClientCredentials.UserName.Password = "abcd1234!";
var result = client.Test();
Console.WriteLine(result);
The configuration automatically generated on the client-side.
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="WSHttpBinding_IService">
<security>
<message clientCredentialType="UserName" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<client>
<endpoint address="http://10.157.13.69:21011/" binding="wsHttpBinding"
bindingConfiguration="WSHttpBinding_IService" contract="ServiceReference1.IService"
name="WSHttpBinding_IService">
<identity>
<certificate encodedValue="blabla… " />
</identity>
</endpoint>
</client>
</system.serviceModel>
In the above example, the client should provide username/password to be authenticated by the server so that call the remote service.
https://learn.microsoft.com/en-us/dotnet/framework/wcf/feature-details/message-security-with-a-user-name-client
Feel free to let me know if there is anything I can help with.
I have been working with this solution where A client application is supposed to access WCF service via Relay.
I have followed this tutorial and was able to access WCF service hosted in console app with client console app.
What I want to achieve is, To access WCF service hosted in local machine via a function app.
So I migrated the code which i did in client console app as shown here to the azure function app.
The client console app had a config file as shown here
I have 2 doubts
I have two doubts.
1) I can not understand how to define endpoint in azure function app which was defined in App.Config file in case of console app as below.
<client>
<endpoint name="RelayEndpoint"
contract="Microsoft.ServiceBus.Samples.IEchoContract"
binding="netTcpRelayBinding"/>
</client>
2) Is there any way to dynamically define endpoint right in the code of function app?
log.Info("C# HTTP trigger function processed a request.");
ServiceBusEnvironment.SystemConnectivity.Mode = ConnectivityMode.AutoDetect;
string serviceNamespace = "MyTestRelay";
string sasKey = "mpQKrfJ6L4Ftdsds2v6Leg3X0e9+Q8MOfjxwghj7xk2qSA=";
Uri serviceUri = ServiceBusEnvironment.CreateServiceUri("sb", serviceNamespace, "EchoService");
TransportClientEndpointBehavior sasCredential = new TransportClientEndpointBehavior();
sasCredential.TokenProvider = TokenProvider.CreateSharedAccessSignatureTokenProvider("RootManageSharedAccessKey", sasKey);
DynamicEndpoint dynamicEndpoint = new DynamicEndpoint(ContractDescription.GetContract(typeof(IEchoContract)), new WSHttpBinding() );
//I AM GETTING ERROR IN Below Line
ChannelFactory<IEchoChannel> channelFactory = new ChannelFactory<IEchoChannel>("RelayEndpoint", new EndpointAddress(serviceUri));
channelFactory.Endpoint.Behaviors.Add(sasCredential);
IEchoChannel channel = channelFactory.CreateChannel();
channel.Open();
Console.WriteLine("Enter text to echo (or [Enter] to exit):");
string input = Console.ReadLine();
while (input != String.Empty)
{
try
{
Console.WriteLine("Server echoed: {0}", channel.Echo(input));
}
catch (Exception e)
{
Console.WriteLine("Error: " + e.Message);
}
input = Console.ReadLine();
}
channel.Close();
channelFactory.Close();
Can anyone suggest how to work with this?
The syntax for creating bindings in code maps to the XML in app.config and you can use like so:
var endpoint = new EndpointAddress(serviceUri);
var binding = new NetTcpRelayBinding()
{
// Example properties that might be in your app.config
ReceiveTimeout = TimeSpan.FromMinutes(2),
SendTimeout = TimeSpan.FromMinutes(2),
};
var channelFactory = new ChannelFactory<IEchoChannel>(binding, endpoint);
I have a WCF service which uses Windows Authentication to view Service Contract and a specfic method in a service is configured to be accessed only by a specific user UserX.
[PrincipalPermission(SecurityAction.Demand,Name="xxx\\UserA")]
In the client side, I need to access the above service method. If I am using a Web Reference -> I add the following
client = new WebRefLocal.Service1();
client.Credentials = new System.Net.NetworkCredential("UserA", "xxxxxx", "test");
But the above cannot be achieved in WCF Service Reference as Client Credentials are read-only. One best way I can achieve the above is Impersonation
https://msdn.microsoft.com/en-us/library/ff649252.aspx.
My question here is
Why ClientCredentials are made readonly in WCF?
How Network Credential work? Will they authenticate the Windows login in client side or server side?
Is there is any way I can achieve the above in WCF aswell without impersonation?
I've done something like this - hope it helps:
var credentials = new ClientCredentials();
credentials.Windows.AllowedImpersonationLevel = TokenImpersonationLevel.Delegation;
credentials.Windows.ClientCredential = new System.Net.NetworkCredential("UserA", "xxxxxx", "test");
client.Endpoint.Behaviors.Remove<ClientCredentials>();
client.Endpoint.Behaviors.Add(credentials);
Used with a BasicHttpBinding with following security settings:
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Windows" proxyCredentialType="Windows" />
</security>
One method you can use is to make use of ChannelFactory when calling the WCF service.
The following code was taken from one of my MVCprojects, hence it has someModelState` validation code, I'm sure you can modify it to suit your needs.
protected R ExecuteServiceMethod<I, R>(Func<I, R> serviceCall) {
R result = default(R);
ChannelFactory<I> factory = CreateChannelFactory<I>();
try {
I manager = factory.CreateChannel();
result = serviceCall.Invoke(manager);
} catch (FaultException<ValidationFaultException> faultException) {
faultException.Detail.ValidationErrors.ToList().ForEach(e => ModelState.AddModelError("", e));
} finally {
if (factory.State != CommunicationState.Faulted) factory.Close();
}
return result;
}
private ChannelFactory<I> CreateChannelFactory<I>() {
UserAuthentication user = GetCurrentUserAuthentication();
ChannelFactory<I> factory = new ChannelFactory<I>("Manager");
if (IsAuthenticated) {
factory.Credentials.UserName.UserName = user.UserName;
factory.Credentials.UserName.Password = user.Password;
}
BindingElementCollection elements = factory.Endpoint.Binding.CreateBindingElements();
factory.Endpoint.Binding = new CustomBinding(elements);
SetDataContractSerializerBehavior(factory.Endpoint.Contract);
return factory;
}
I have a C# app which is calling a WCF service via a proxy server.
Both the proxy and the WCF service require (different) credentials.
I am using the svcutil-generated proxy classes to access the WCF service.
When I switch off the proxy server's requirement for credentials then I can access the WCF service fine so all that I want is to know where to apply the credentials for the proxy server (I'm using Fiddler in my dev environment).
I've read various posts which say to set the credentials in client.ClientCredentials and this seems to work for either the proxy server credentials OR the WCF service credentials but I can't store both.
If I put the proxy server credentials in client.ClientCredentials then the request hits the WCF service but then gets rejected.
If I put the WCF service credentials in client.ClientCredentials then the request does not get past the proxy server.
Is there a way to supply two different sets of credentials so I can get authenticated by the proxy server and the WCF service? I need to do this in code, not in the config file.
Code is below:
public class Runner
{
public int GetAvailableFacilities(int timeoutInSeconds, string uri, string userName, string password)
{
FacilitySearchServiceClient client = null;
try
{
client = SetClient(timeoutInSeconds, uri, userName, password, client);
string outputMessage = null;
int[] availableFacilities = client.GetAvailableFacilities(out outputMessage);
return availableFacilities.Length;
}
finally
{
if (client != null)
{
client.Close();
}
}
}
private FacilitySearchServiceClient SetClient(int timeoutInSeconds, string uri, string wcfServiceUserName, string wcfServicePassword, FacilitySearchServiceClient client)
{
string proxyServerUsername = "1";//Fiddler
string proxyServerPassword = "1";//Fiddler
client = new FacilitySearchServiceClient(ConfigureServiceBinding(timeoutInSeconds), new EndpointAddress(uri));
//If this is the only uncommented call to SetServiceCredentials the proxy server transmits the request
//to the wcf service which then rejects the authentication attempt.
SetServiceCredentials(client.ClientCredentials, proxyServerUsername, proxyServerPassword);
//If this is the only uncommented call to SetServiceCredentials the proxy server rejects the authentication attempt,
//resulting in an EndpointNotFoundException.
SetServiceCredentials(client.ClientCredentials, wcfServiceUserName, wcfServicePassword);
return client;
}
protected static void SetServiceCredentials(ClientCredentials credentials, string userName, string password)
{
credentials.UserName.UserName = userName;
credentials.UserName.Password = password;
}
protected CustomBinding ConfigureServiceBinding(int timeoutInSeconds)
{
CustomBinding binding = new CustomBinding();
SecurityBindingElement sbe = SecurityBindingElement.CreateUserNameOverTransportBindingElement();
sbe.IncludeTimestamp = false;
sbe.EnableUnsecuredResponse = true;
sbe.AllowInsecureTransport = true;
binding.Elements.Add(sbe);
binding.Elements.Add(new TextMessageEncodingBindingElement(MessageVersion.Soap11, System.Text.Encoding.UTF8));
binding.Elements.Add(CreateHttpsBindingElement(Const.ProxyServerUrl));
return binding;
}
/// <summary>
/// Sets up the element needed for the web service call.
/// </summary>
private static HttpsTransportBindingElement CreateHttpsBindingElement(string proxyUri)
{
HttpsTransportBindingElement tpt = new HttpsTransportBindingElement();
tpt.TransferMode = TransferMode.Streamed;
tpt.MaxReceivedMessageSize = Int32.MaxValue;
tpt.MaxBufferSize = Int32.MaxValue;
tpt.AuthenticationScheme = System.Net.AuthenticationSchemes.Anonymous;
if (string.IsNullOrEmpty(proxyUri) == false)
{
tpt.ProxyAddress = new Uri(proxyUri);
tpt.UseDefaultWebProxy = false;
tpt.ProxyAuthenticationScheme = System.Net.AuthenticationSchemes.Basic;
}
return tpt;
}
}
I ran in to this exact same problem a few months back. The problem is the WCF client proxy does not expose a separate property for specifying proxy server credentials like say, the HttpWebRequest object which exposes a proxy property of type System.Net.WebProxy. In that case you could just use the Credentials property of the System.Net.WebProxy type to achieve what you are trying to do. In your case you can do this for your WCF client by setting the proxy credentials for all the web requests made by your .NET application by modifying the Application_Start method in Global.asax.cs (assuming that your client is also a web app). Otherwise you could just use this code in the appropriate startup method of your client application.
protected void Application_Start(Object sender, EventArgs e)
{
var proxy = new WebProxy("myproxyservername", <myproxyPort>) { Credentials = new System.Net.NetworkCredential("yourproxyusername", "yourproxypassword") };
WebRequest.DefaultWebProxy = proxy;
}
I'm trying to add ad-hoc discovery to a simple WCF service-client setup (currently implemented by self hosting in a console app). Debugging using VS2010 on windows 7, and doing whatever I can find in online tutorial, but still - the discovery client simply finds nothing. Needless to say if I open a client to the correct service endpoint I can access the service from the client.
service code:
using (var selfHost = new ServiceHost(typeof(Renderer)))
{
try
{
selfHost.Open();
...
selfHost.Close();
service app.config:
<?xml version="1.0"?>
<configuration>
<system.serviceModel>
<services>
<service name="TestApp.Renderer">
<host>
<baseAddresses>
<add baseAddress="http://localhost:9000" />
</baseAddresses>
</host>
<endpoint address="ws" binding="wsHttpBinding" contract="TestApp.IRenderer"/>
<endpoint kind="udpDiscoveryEndpoint"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceDiscovery/>
<serviceMetadata httpGetEnabled="True"/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
client discovery code:
DiscoveryClient discoveryClient = new DiscoveryClient(new UdpDiscoveryEndpoint());
var criteria = new FindCriteria(typeof(IRenderer)) { Duration = TimeSpan.FromSeconds(5) };
var endpoints = discoveryClient.Find(criteria).Endpoints;
The 'endpoints' collection always comes out empty. I've tried running the service and client from the debugger, from a command line, from an admin command line - everything, but to no avail (all on the local machine, of course, not to mantion I'll need it running on my entire subnet eventually)
Any help would be appreciated :-)
Here is a super simple discovery example. It does not use a config file, it is all c# code, but you can probably port the concepts to a config file.
share this interface between host and client program (copy to each program for now)
[ServiceContract]
public interface IWcfPingTest
{
[OperationContract]
string Ping();
}
put this code in the host program
public class WcfPingTest : IWcfPingTest
{
public const string magicString = "djeut73bch58sb4"; // this is random, just to see if you get the right result
public string Ping() {return magicString;}
}
public void WcfTestHost_Open()
{
string hostname = System.Environment.MachineName;
var baseAddress = new UriBuilder("http", hostname, 7400, "WcfPing");
var h = new ServiceHost(typeof(WcfPingTest), baseAddress.Uri);
// enable processing of discovery messages. use UdpDiscoveryEndpoint to enable listening. use EndpointDiscoveryBehavior for fine control.
h.Description.Behaviors.Add(new ServiceDiscoveryBehavior());
h.AddServiceEndpoint(new UdpDiscoveryEndpoint());
// enable wsdl, so you can use the service from WcfStorm, or other tools.
var smb = new ServiceMetadataBehavior();
smb.HttpGetEnabled = true;
smb.MetadataExporter.PolicyVersion = PolicyVersion.Policy15;
h.Description.Behaviors.Add(smb);
// create endpoint
var binding = new BasicHttpBinding(BasicHttpSecurityMode.None);
h.AddServiceEndpoint(typeof(IWcfPingTest) , binding, "");
h.Open();
Console.WriteLine("host open");
}
put this code in the client program
private IWcfPingTest channel;
public Uri WcfTestClient_DiscoverChannel()
{
var dc = new DiscoveryClient(new UdpDiscoveryEndpoint());
FindCriteria fc = new FindCriteria(typeof(IWcfPingTest));
fc.Duration = TimeSpan.FromSeconds(5);
FindResponse fr = dc.Find(fc);
foreach(EndpointDiscoveryMetadata edm in fr.Endpoints)
{
Console.WriteLine("uri found = " + edm.Address.Uri.ToString());
}
// here is the really nasty part
// i am just returning the first channel, but it may not work.
// you have to do some logic to decide which uri to use from the discovered uris
// for example, you may discover "127.0.0.1", but that one is obviously useless.
// also, catch exceptions when no endpoints are found and try again.
return fr.Endpoints[0].Address.Uri;
}
public void WcfTestClient_SetupChannel()
{
var binding = new BasicHttpBinding(BasicHttpSecurityMode.None);
var factory = new ChannelFactory<IWcfPingTest>(binding);
var uri = WcfTestClient_DiscoverChannel();
Console.WriteLine("creating channel to " + uri.ToString());
EndpointAddress ea = new EndpointAddress(uri);
channel = factory.CreateChannel(ea);
Console.WriteLine("channel created");
//Console.WriteLine("pinging host");
//string result = channel.Ping();
//Console.WriteLine("ping result = " + result);
}
public void WcfTestClient_Ping()
{
Console.WriteLine("pinging host");
string result = channel.Ping();
Console.WriteLine("ping result = " + result);
}
on the host, simply call the WcfTestHost_Open() function, then sleep forever or something.
on the client, run these functions. It takes a little while for a host to open, so there are several delays here.
System.Threading.Thread.Sleep(8000);
this.server.WcfTestClient_SetupChannel();
System.Threading.Thread.Sleep(2000);
this.server.WcfTestClient_Ping();
host output should look like
host open
client output should look like
uri found = http://wilkesvmdev:7400/WcfPing
creating channel to http://wilkesvmdev:7400/WcfPing
channel created
pinging host
ping result = djeut73bch58sb4
this is seriously the minimum I could come up with for a discovery example. This stuff gets pretty complex fast.
Damn! it was the firewall... for some reason all UDP communication was blocked - disabling the firewall solved the problem. Now I only need to figure out the correct firewall configuration...