JAX-WS Client CXF WS-Policy Issue - authentication

I have to implement a JAX-WS-Client which consumes a service from an external partner. I use Apache CXF. The service defines two WS-Policies for authentication in the wsdl - KerberosToken and UsernameToken. Since the service is from an external partner it cant be changed.
The problem: Authentication fails at Kerberos-Authentication since I want to use
the simple UsernameToken-Authentication.
WSLD-Policy-Part:
<wsp:Policy xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy"
xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
wsu:Id="SecurityServiceUsernameUnsecureTransportPolicy">
<wsp:ExactlyOne>
<wsp:All>
<sp:SupportingTokens xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
<wsp:Policy>
<sp:KerberosToken sp:IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/AlwaysToRecipient">
<wsp:Policy>
<sp:WssGssKerberosV5ApReqToken11/>
</wsp:Policy>
</sp:KerberosToken>
</wsp:Policy>
</sp:SupportingTokens>
</wsp:All>
<wsp:All>
<sp:SupportingTokens xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
<wsp:Policy>
<sp:UsernameToken sp:IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/AlwaysToRecipient">
<wsp:Policy>
<sp:WssUsernameToken10/>
</wsp:Policy>
</sp:UsernameToken>
</wsp:Policy>
</sp:SupportingTokens>
</wsp:All>
</wsp:ExactlyOne>
</wsp:Policy>
Setting Username/Password at CXF-Endpoint:
public void addAuthenticationProperties( Endpoint endpoint ) {
endpoint.put( SecurityConstants.USERNAME, userName );
endpoint.put( SecurityConstants.PASSWORD, password );
}
As I understand the -Tag means, that if any (excatly one) of this policies is fullfilled move on. But CXF does not even try to fullfill the UsernameToken - Policy.
If I remove the -Block for KerberosToken authentication works fine, but in production this is not possible.
Any hints? If there is an error in the wsdl or in my approach please let me know. And please be detailed - I am a noob in this field.
Thanks in advance!

Some days later I found a workaround for this problem - wouldn't call it solution ;-)
At first the old version:
CXF generated a class ExampleWS_Service and a corresponding interface ExampleWS. So I used the ExampleWS_Service to set everthing up and invoke the service:
// creating Port
URL url = new URL( config.getSchema(), config.getHost(), config.getPort(), config.getPath() );
ExampleWS_Service service = new ExampleWS_Service( url );
ExampleWS port = service.getExampleWSPort();
// Adding authentication-info
Client client = ClientProxy.getClient( port );
Endpoint cxfEndpoint = client.getEndpoint();
cxfEndpoint.put( SecurityConstants.USERNAME, userName );
cxfEndpoint.put( SecurityConstants.PASSWORD, password );
...
// invoke service
port.doSomething( [data] );
The workaround:
I switched to JaxWsProxyFactoryBean and setting everthing up. In this case a WSS4JOutInterceptor is needed to put authentication information in the request-header. Some code:
URL url = new URL( config.getSchema(), config.getHost(), config.getPort(), config.getPath() );
JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
factory.setServiceClass( ExampleWS.class );
factory.setAddress( url.toString() );
factory.setBindingId( "http://schemas.xmlsoap.org/wsdl/soap12/" );
ExampleWS port = ( ExampleWS )factory.create();
// Adding authentication-info using WSS4JOutInterceptor
Client client = ClientProxy.getClient( port );
Endpoint cxfEndpoint = client.getEndpoint();
Map<String, Object> outProps = new HashMap<>();
outProps.put( WSHandlerConstants.ACTION, WSHandlerConstants.USERNAME_TOKEN );
outProps.put( WSHandlerConstants.USER, userName );
outProps.put( WSHandlerConstants.PASSWORD_TYPE, passwordType );
outProps.put( WSHandlerConstants.PW_CALLBACK_REF, [Instance of javax.security.auth.callback.CallbackHandler] );
WSS4JOutInterceptor wssOut = new WSS4JOutInterceptor( outProps );
cxfEndpoint.getOutInterceptors().add( wssOut );
...
// invoke service
port.doSomething( [data] );
I don't know why exactly this workaround actually work, but it does :-)
Perhaps someone of you can give me so enlightenment.

CXF doesn't handle multiple policy options on the outbound side for security, only on the inbound side. So your only option is tighten the policy to either Kerberos or UsernameToken, depending on whatever policy you want your client to use.

Related

Mutual Authentication with Reactive Netty on restricted urls

I am using spring cloud gateway to front a legacy application so that we can start migrating things behind the scenes. Some of the urls that are hosted by the application are public facing and some are device restricted. We control the devices and they use a browser client to access the restricted urls. We have mutual authentication setup for the device restricted urls on the server using tomcat and security constraints like this in web.xml:
<security-constraint>
<web-resource-collection>
<web-resource-name>Certificate Content</web-resource-name>
<!-- URL for authentication endpoint - this is locked down with the role assigned by tomcat -->
<url-pattern>/rest/secure/url1</url-pattern>
<url-pattern>/rest/secure/url2</url-pattern>
<url-pattern>/rest/secure/url3</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>certificate</role-name>
</auth-constraint>
<user-data-constraint>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
</user-data-constraint>
</security-constraint>
<!-- All other endpoints- force the switch from http to https with transport-guarantee -->
<security-constraint>
<web-resource-collection>
<web-resource-name>Protected Context</web-resource-name>
<url-pattern>/*</url-pattern>
</web-resource-collection>
<user-data-constraint>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
</user-data-constraint>
</security-constraint>
<login-config>
<auth-method>CLIENT-CERT</auth-method>
</login-config>
<security-role>
<role-name>certificate</role-name>
</security-role>
That is coupled with a truststore setup in tomcat's server.xml (I can add it, but I don't think that is relevant to this conversation).
My goal is to implement a similar setup in spring cloud gateway which is using reactive netty under-the-hood and remove the web.xml restrictions from the legacy application. I think I could switch it to using tomcat and probably get the web.xml from above to work, but I'd rather stick to the performance benefits of using reactive netty.
Key Goals:
Only deploy one api gateway for the app. The number of urls that
require mutual auth is very small so I'd rather not include a whole
other container to manage just to support them.
Do not ask for a client cert on the public urls.
Require valid client certs for the restricted urls.
I've setup mutual authentication and can get it to work with need/want/none as expected (truststores setup, etc), but it applies to ALL urls. I've also setup X509 security restrictions and that all seems to work.
I think what I want to setup is tsl renegotiation using the SslHandler after the http request is decrypted (so that I can access the url) based on the path. But I'm having trouble with the details and I've failed at finding any examples that incorporate spring-boot applications using reactive netty to do a tsl renegotiation. Any tips on how to perform a renegotiation of the ssl connection with needClientAuth set to true would be appreciated. I think I need to invalidate the session or something because when I try to do it manually it appears that it is skipping negotiation because the connection is already marked as negotiated in the ssl engine.
This is one of the iterations I've tried (this doesn't restrict on urls, but I plan to add that after I get this working):
#Component
public class NettyWebServerFactoryGatewayCustomizer implements WebServerFactoryCustomizer<NettyReactiveWebServerFactory> {
private static final Logger LOG = LoggerFactory.getLogger(NettyWebServerFactoryGatewayCustomizer.class);
#Override
public void customize(NettyReactiveWebServerFactory serverFactory) {
serverFactory.addServerCustomizers(httpServer -> {
httpServer = httpServer.wiretap(true);
return httpServer.tcpConfiguration(tcpServer -> {
tcpServer = tcpServer.doOnConnection(connection ->
connection.addHandler("request client cert",
new SimpleChannelInboundHandler<HttpRequest>() {
#Override
protected void channelRead0(ChannelHandlerContext ctx, HttpRequest httpRequest) {
LOG.error("HttpRequest: {}", httpRequest);
final ChannelPipeline pipeline = ctx.pipeline();
final SslHandler sslHandler = pipeline.get(SslHandler.class);
final SSLEngine sslEngine = sslHandler.engine();
sslEngine.setNeedClientAuth(true);
sslHandler.renegotiate()
.addListener(future -> ctx.fireChannelRead(httpRequest));
}
}
)
);
return tcpServer;
});
});
}
}
I see it performing the renegotiation in the debugger, but it still seems to be set to client auth none (as set in the application.properties) instead of need as set in the code before renegotiation. I've tried sslEngine.getSession().invalidate(); but that didn't help. I've also tried generating a new ssl handler from the ssl provider but that seemed to really screw things up.
Thank you for any help provided.
Edit: Doing more research it appears that this approach is not appropriate going forward since ssl renegotiation is being dropped entirely in tsl 1.3 (see https://security.stackexchange.com/a/230327). Is there a way to perform the equivalent of SSL verify client post handshake as described here: https://www.openssl.org/docs/manmaster/man3/SSL_verify_client_post_handshake.html ?
Edit2: Looks like this was an issue where TLS1.3 post handshake was not supported by the browser I was testing with. Setting the server to just accept TLS 1.2 seemed to work. Not sure if there is a better way to solve this but this is what I added to my application.properties:
server.ssl.enabled-protocols=TLSv1.2
Here is what I used to get it to work. I'm going to leave out the spring security side of it since that is separate from requesting the certificate from the client.
There are so many ways to configure the child pipeline that is used to process the request. Please let me know if there is a more accepted way to configure it.
Configure the HttpServer by adding to the bootstrap pipeline that is applied when a connection is established with the client:
#Component
public class NettyWebServerFactoryGatewayCustomizer implements WebServerFactoryCustomizer<NettyReactiveWebServerFactory> {
private static final HttpRenegotiateClientCertHandler HTTP_RENEGOTIATE_CLIENT_CERT_HANDLER =
new HttpRenegotiateClientCertHandler(SecurityConfig.X509_PROTECTED_ENDPOINTS);
#Override
public void customize(NettyReactiveWebServerFactory serverFactory) {
serverFactory.addServerCustomizers(NettyWebServerFactoryGatewayCustomizer::addRenegotiateHandlerToHttpServer);
}
private static HttpServer addRenegotiateHandlerToHttpServer(HttpServer httpServer) {
return httpServer.tcpConfiguration(NettyWebServerFactoryGatewayCustomizer::addRenegotiateHandlerToTcpServer);
}
private static TcpServer addRenegotiateHandlerToTcpServer(TcpServer server) {
return server.doOnBind(NettyWebServerFactoryGatewayCustomizer::addRenegotiateHandlerToServerBootstrap);
}
private static void addRenegotiateHandlerToServerBootstrap(ServerBootstrap serverBootstrap) {
BootstrapHandlers.updateConfiguration(
serverBootstrap,
HttpRenegotiateClientCertHandler.NAME,
NettyWebServerFactoryGatewayCustomizer::addRenegotiateHandlerToChannel
);
}
private static void addRenegotiateHandlerToChannel(ConnectionObserver connectionObserver, Channel channel) {
final ChannelPipeline pipeline = channel.pipeline();
pipeline.addLast(HttpRenegotiateClientCertHandler.NAME, HTTP_RENEGOTIATE_CLIENT_CERT_HANDLER);
}
}
Child Handler that performs the renegotiation:
#ChannelHandler.Sharable
public class HttpRenegotiateClientCertHandler extends SimpleChannelInboundHandler<HttpRequest> {
public static final String NAME = NettyPipeline.LEFT + "clientRenegotiate";
private static final PathPatternParser DEFAULT_PATTERN_PARSER = new PathPatternParser();
private final Collection<PathPattern> pathPatterns;
public HttpRenegotiateClientCertHandler(String ... antPatterns) {
Assert.notNull(antPatterns, "patterns cannot be null");
Assert.notEmpty(antPatterns, "patterns cannot be empty");
Assert.noNullElements(antPatterns, "patterns cannot have null items");
pathPatterns = Arrays.stream(antPatterns)
.map(DEFAULT_PATTERN_PARSER::parse)
.collect(Collectors.toSet());
}
#Override
protected void channelRead0(ChannelHandlerContext ctx, HttpRequest request) {
if (shouldNotRenegotiate(request)) {
ctx.fireChannelRead(request);
return;
}
final ChannelPipeline pipeline = ctx.pipeline();
final SslHandler sslHandler = pipeline.get(SslHandler.class);
final SSLEngine sslEngine = sslHandler.engine();
sslEngine.setNeedClientAuth(true);
sslHandler.renegotiate()
.addListener(renegotiateFuture -> ctx.fireChannelRead(request));
}
/**
* Determine if the request uri matches the configured uris for this handler.
* #param request to match the path from.
* #return true if any of the path patterns are matched.
*/
private boolean shouldNotRenegotiate(HttpRequest request) {
final String requestUri = request.uri();
final PathContainer path = PathContainer.parsePath(requestUri);
return pathPatterns.stream()
.noneMatch(matcher -> matcher.matches(path));
}
}
And these configurations in application.properties:
# Setup Client Auth Truststore:
server.ssl.trust-store=<path to truststore>
server.ssl.trust-store-password=<truststore password>
server.ssl.trust-store-type=<truststore type>
# Set to none by default so we do not ask for client auth until needed.
server.ssl.client-auth=none
# This is specifically not including TLSv1.3 because there are issues
# with older browsers' implementation of TLSv1.3 that prevent verify
# client post handshake client from working.
server.ssl.enabled-protocols=TLSv1.2
Edit: Updated because handler gateway route code wasn't being invoked properly.

Rampart: Define password without using CallbackHandler

I have the following working code, that successfully connects to a WS using WSSecurity with UsernameToken authentication:
public void addValidation(
Stub stub) throws Exception {
ServiceClient serviceClient = stub._getServiceClient();
serviceClient.engageModule("rampart");
Options options = serviceClient.getOptions();
options.setProperty(
WSSHandlerConstants.OUTFLOW_SECURITY,
getOutflowConfiguration());
serviceClient.setOptions(options);
}
private Parameter getOutflowConfiguration() {
OutflowConfiguration outflowConfiguration =
new OutflowConfiguration();
outflowConfiguration.setActionItems(
"UsernameToken");
outflowConfiguration.setUser(
this.username);
outflowConfiguration.setPasswordType(
"PasswordText");
outflowConfiguration.setPasswordCallbackClass(
"es.ssib.otic.inte_portafib.cliente_custodia_axis2.PWCBHandler");
return
outflowConfiguration.getProperty();
}
Now, since I want to pass the password programatically, I am trying to configure the password as a parameter, but it does not work.
I have tried replacing the "outflow configuration" with
options.setUserName(
this.username);
options.setPassword(
this.password);
But those fields are ignored by Axis 2 completely.
I have tried using this example
public void addValidation(
Stub stub) throws Exception {
ServiceClient serviceClient =
stub._getServiceClient();
Options options = serviceClient.getOptions();
options.setUserName(this.username);
options.setPassword(this.password);
options.setProperty(
RampartMessageData.KEY_RAMPART_OUT_POLICY,
loadPolicy());
serviceClient.engageModule("rampart");
}
private Policy loadPolicy() throws XMLStreamException, IOException {
InputStream resource = new FileInputStream([path to policy.xml]");
StAXOMBuilder builder = new StAXOMBuilder(resource);
return PolicyEngine.getPolicy(builder.getDocumentElement());
}}
with this policy file
<wsp:Policy wsu:Id="UsernameToken" xmlns:wsu=
"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy">
<wsp:ExactlyOne>
<wsp:All>
<sp:SupportingTokens
xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
<wsp:Policy>
<sp:UsernameToken sp:IncludeToken="http://docs.oasis-open.org/
ws-sx/ws-securitypolicy/200702/IncludeToken/AlwaysToRecipient"/>
</wsp:Policy>
</sp:SupportingTokens>
</wsp:All>
</wsp:ExactlyOne>
</wsp:Policy>
but it fails with the message:
Incorrect inclusion value: -1
I am using Rampart 1.5 with Axis2 1.4
UPDATE: I know how to make the CallbackHandler check a static constant, or to invoke some data object to get the password. But I do not want to do that.

Service Fabric - how do I expose a wcf service externally

I have looked through the docs on wcf on azure service fabric but it seems the only examples show how to expose it to other fabric services. I want to expose a wcf endpoint like I would a rest end point, so I can map it to a public IP address.
Any ideas?
I had to solve this exact scenario.
You don't need to return a listener at all. You need to open an endpoint in the 'Service Manifest.xml'. You bind the ssl cert here etc (I'll assume that you know this part).
<Endpoint Name="Test.WcfTypeEndpoint" Protocol="https" Type="Input" CertificateRef="MySSL" Port="44330" />
You can now open Service Hosts and it will route requests to them. Use a strong wildcard in the binding when opening the service - otherwise it won't resolve on the node that it ends up on.
public class InternalBinding : Binding
{
private readonly HttpsTransportBindingElement _transport;
public InternalBinding()
{
_transport = new HttpTransportBindingElement
{
HostNameComparisonMode = HostNameComparisonMode.StrongWildcard,
// etc
}
}
}

Sharing ASP.NET simplemembership authentication across web roles and client applications

I've been trying to figure this out for a while now, reading a lot of blogs, MSDN documentation, sample code and other stackoverflow questions and have yet to get this to work.
Here is my scenario:
I am using Windows Azure to host two web roles. One is my MVC4 web API, the other is my MVC4 web app which uses the web API. I also have a number of client applications using .NET that will access the web API.
So my main components are:
Web API
Web App
.NET Client
I want to use forms authentication that is 'hosted' in the Web App. I am using the built in simplemembership authentication mechanism and it works great. I can create and log in to accounts in the Web App.
Now I also want to use these same accounts to authenticate the Web API, both from the Web App and any .NET client apps.
I've read numerous ways to do this, the simplest appearing to be using Basic Authentication on the Web API. Currently I am working with this code as it appears to solve my exact problem: Mixing Forms Authentication, Basic Authentication, and SimpleMembership
I can't get this to work. I log in successfully to my Web App (127.0.0.1:81) and when I try to call a Web API that requires authentication (127.0.0.1:8081/api/values for example) the call fails with a 401 (Unauthorized) response. In stepping through the code, WebSecurity.IsAuthenticated returns false. WebSecurity.Initialized returns true.
I've implemented this code and am trying to call my Web API from my Web App (after logging in) with the following code:
using ( var handler = new HttpClientHandler() )
{
var cookie = FormsAuthentication.GetAuthCookie( User.Identity.Name, false );
handler.CookieContainer.Add( new Cookie( cookie.Name, cookie.Value, cookie.Path, cookie.Domain ) );
using ( var client = new HttpClient() )
{
//client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(
// "Basic",
// Convert.ToBase64String( System.Text.ASCIIEncoding.ASCII.GetBytes(
// string.Format( "{0}:{1}", User.Identity.Name, "123456" ) ) ) );
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(
"Cookie",
Convert.ToBase64String( System.Text.ASCIIEncoding.ASCII.GetBytes( User.Identity.Name ) ) );
string response = await client.GetStringAsync( "http://127.0.0.1:8080/api/values" );
ViewBag.Values = response;
}
}
As you can see, I've tried both using the cookie as well as the username/password. Obviously I want to use the cookie, but at this point if anything works it will be a good step!
My ValuesController in my Web API is properly decorated:
// GET api/values
[BasicAuthorize]
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
In my Global.asax.cs in my Web API, I am initializing SimpleMembership:
// initialize our SimpleMembership connection
try
{
WebSecurity.InitializeDatabaseConnection( "AzureConnection", "User", "Id", "Email", autoCreateTables: false );
}
catch ( Exception ex )
{
throw new InvalidOperationException( "The ASP.NET Simple Membership database could not be initialized. For more information, please see http://go.microsoft.com/fwlink/?LinkId=256588", ex );
}
This succeeds and WebSecurity later says that it is initialized so I guess this part is all working properly.
My config files have matching authentication settings as required per MSDN.
Here is the API config:
<authentication mode="Forms">
<forms protection="All" path="/" domain="127.0.0.1" enableCrossAppRedirects="true" timeout="2880" />
</authentication>
<machineKey decryption="AES" decryptionKey="***" validation="SHA1" validationKey="***" />
Here is the Web App config:
<authentication mode="Forms">
<forms loginUrl="~/Account/Login" protection="All" path="/" domain="127.0.0.1" enableCrossAppRedirects="true" timeout="2880" />
</authentication>
<machineKey decryption="AES" decryptionKey="***" validation="SHA1" validationKey="***" />
Note, I am trying this locally (hence the 127.0.0.1 domain), but referencing a database hosted on Azure.
I haven't got to trying any of this from a .NET client application since I can't even get it working between web roles. For the client app, ideally I would make a web call, passing in username/password, retrieve the cookie, and then use the cookie for further web API requests.
I'd like to get what I have working as it seems pretty simple and meets my requirements.
I have not yet tried other solutions such as Thinktecture as it has way more features than I need and it doesn't seem necessary.
What am I missing?
Well, this is embarrassing. My main problem was a simple code error. Here is the correct code. Tell me you can spot the difference from the code in my question.
using ( var handler = new HttpClientHandler() )
{
var cookie = FormsAuthentication.GetAuthCookie( User.Identity.Name, false );
handler.CookieContainer.Add( new Cookie( cookie.Name, cookie.Value, cookie.Path, cookie.Domain ) );
using ( var client = new HttpClient( handler ) )
...
}
Once that was fixed, I started getting 403 Forbidden errors. So I tracked that down and made a small change to the BasicAuthorizeAttribute class to properly support the [BasicAuthorize] attribute when no role is specified.
Here is the modified code:
private bool isAuthorized( string username )
{
// if there are no roles, we're good!
if ( this.Roles == "" )
return true;
bool authorized = false;
var roles = (SimpleRoleProvider)System.Web.Security.Roles.Provider;
authorized = roles.IsUserInRole( username, this.Roles );
return authorized;
}
With that change basic authentication by passing in the forms cookie works!
Now to get non-web client apps working and then refactor the Web App as recommended.
I hope this helps someone in the future!

Silverlight WCF Self Hosting seemed not to locate ClientAccessPolicy.xml

I've created WCF self hosting service in local machine and silverlight App gets data
from this service and send it to remote server. It worked well for more than a month
but suddenly stopped complaining well known errors clientaccesspolicy.xml not resolved.
After spending quite some time to debug, I realized it failed since the remote server
address has been changed into IP address instead of domain addresss, for example
http://2xx.1xx.223 iso http://www.myserver.com, but domain address is not avaliable anymore
so I can't reproduce it and not sure really address changing is the criminal.
It still works fine if webserver and self hosting service both are running in my dev
machine and I can see file in my browser as "http://localhost:8000/clientaccesspolicy.xml"
but 404 error if typed "http://my-machine-name:8000/clientaccesspolicy.xml".
As I read some blogs,clientaccesspolicy.xml should be located in 80 port of local machine
but dno't know how to do and not sure it makes the problem.
My service host is configured as follows;
string baseAddress = "http://localhost:8000";
//Create a ServiceHost for the OPCService type and
//provide the base address.
_serviceHost = new ServiceHost(typeof(OpcService), new Uri(baseAddress));
_serviceHost.AddServiceEndpoint(typeof(IOpcService), new BasicHttpBinding(), new Uri(baseAddress + "/OpcService"));
_serviceHost.AddServiceEndpoint(typeof(IPolicyRetriever), new WebHttpBinding(), "").Behaviors.Add(new WebHttpBehavior());
And clientacceccpolicy.xml is used through interface
private Stream StringToStream(string result)
{
WebOperationContext.Current.OutgoingResponse.ContentType = "application/xml";
return new MemoryStream(Encoding.UTF8.GetBytes(result));
}
public Stream GetSilverlightPolicy()
{
string result = #"<?xml version=""1.0"" encoding=""utf-8""?>
<access-policy>
<cross-domain-access>
<policy>
<allow-from http-request-headers=""*"">
<domain uri=""*""/>
</allow-from>
<grant-to>
<resource path=""/"" include-subpaths=""true""/>
</grant-to>
</policy>
</cross-domain-access>
</access-policy>";
return StringToStream(result);
}
And silverlight client uses service with proxy without ServiceReferences.ClientConfig
but with service refrence to easily get web methods.
public class ServiceProxy
{
private const string ServiceEndPoint = "http://localhost:8000/OpcService";
private static Uri _serviceMap = new Uri(ServiceEndPoint, UriKind.Absolute);
public static T GetProxyFor<T>()
{
return new ChannelFactory<T>(new BasicHttpBinding(), new EndpointAddress(_serviceMap)).CreateChannel();
}
[Export]
public IOpcService SyrOpcService
{
get { return GetProxyFor<IOpcService>(); }
}
public static SYR.HMI.OpcProxy.ServiceReference.OpcServiceClient GetProxy()
{
return new SYR.HMI.OpcProxy.ServiceReference.OpcServiceClient();
}
}
I read many threads here and google but not quite like mine and still vague to me
which one is the problem, IP address change or clientaccesspolicy file location.
Kind advice would be appreciated.
Thank you in advance.
HK.Lee
I made small SL test app with 2 small methods and change endpoint address of ClientConfig
into http://ipv4.fiddler:8000 instead of http://locahost:8000.
Fiddler looks clientaccesspolicy.xml from 127.0.0.1 iso localhost,
so I changed my SL client proxy address into 127.0.0.1 instead of localhost.
Everything works fine.
It's funny why localhost does not work if xap is downloaded from IP address vc domain name?
I don't know the details but anyone give some advice.
HK.lee