Is there a way to restrict access to an ASMX Webservice, i.e. the asmx page and its WSDL? - web-services

I have a C# .net webservice that I need to restrict access to. I already require my consumers to use a username and password to call the service. But, is there a way to restrict access to the actual asmx page and the WSDL? I would need to restrict access to the webservice by username/password and IP address. If a user did not have the correct credentials, I would not want them to know what webmethods exist in the webservice.
Can this be done though IIS? I know that I can restrict IP addresses through IIS, but can I also use usernames/passwords?
Is there any other way to do this outside of IIS, maybe using C#.net?

Well, since it's ASMX you have the entire ASP.NET runtime stack at your disposal.
Step #1 - managing the resource through .config
Apply a <location> tag for the resources you want secured. Assuming it's a single ASMX file you can simply do the following in your web.config:
<location path="MyWebService.asmx">
<system.web>
<!-- resource specific options will go here -->
</system.web>
</location>
Step #2 - authenticating your users
You need to decide how you're actually going to authenticate users. There are several ways to do this and several authentication standards you could leverage. You need to pick the approach that's the right fit for you.
If you're on an intranet and are using Windows authentication I would highly suggest leveraging that because it's truly the simplest option to get setup. However, if your services are being accessed over the internet then Windows authenticatio is not really an option and you need to choose from a web standard. The simplest of those is Basic Authentication, but you should only use this over SSL since the username/password are not encrypted (only base64 encoded). The next step up from that is Digest authentication which doesn't require SSL because the username/password are sent using an MD5 hash. For the ultimate you can go with SSL v3 where you issue a specific client certificate to each user of your API.
Now, which option you select for security dictates what else needs to be done. If you choose Windows security, it's as easy as adding the following element to the <system.web> element we started with in Step #1:
<authentication mode="Windows" />
The remainder of the security protocols are going to require a little more work. ASP.NET doesn't provide intrinsic support for Basic, Digest or SSL v3. Technically you can leverage IIS to do this type of authentication for you, but it's always going to map to a Windows user. If that's an option for you, then simply leave the <authentication mode="Windows" /> element and configure IIS accordingly. If, however, that is not an option, either because you simply have no control over IIS/ActiveDirectory or you need to authenticate against a custom user database, then that means that you need to hook up a custom HttpModule to provide support for these security protocols.
Step #3 - securing the resource
The simplest approach to securing the resource is to basically say: "don't let anyone who hasn't successfully authenticated in some way into this resource". This is done using the following authorization configuration:
<authorization>
<deny users="?" />
</authorization>
If you wanted to only allow certain users you could change to do the following instead:
<authorization>
<deny users="*" />
<allow users="jdoe, msmith" />
</authorization>
Another approach is to define roles (groups) and simply lock the resource down to a special role which you put the users who you want to access the resource into.
<authorization>
<deny users="*" />
<allow roles="My Service Users" />
</authorization>
This maps well to Windows authentication because you can just setup a Windows group and let your MIS team manage which users are in that group using ActiveDirectory. However, the feature also works just fine for non-Windows authentication assuming the security implementation you've used exposes roles via its IPrincipal implementation.

I don't know how practical this is for you, but you could consider upgrading to WCF. WCF is fully backward compatible with ASMX web services, and lets you control whether or not the WSDL is exposed by defining a MEX (metadata exchange) endpoint. No MEX endpoint, no WSDL.

You can stop WSDL being shown by removing the Documentation protocol from the element in Machine.config
Update:
Web Services authentication - best practices?
If your users have usernames/passwords you can use HTTP basic authentication via HTTPS.
You can also implement it in a slightly differnt way. The first call to your web service should be the authentication method. Client authenticates and receives an authentication token. This token should be presented to all other methods exposed by your web service.

Two options: Create an entirely different site on a different port with locked down permissions. This has the advantage of providing some amount of "security through obscurity" (half joking...) Or you can add a new Application under your site(same port, different path), on a different app pool and assign permissions that way.
In either case, your web service isn't going to be able to talk with the various ASP.NET "things" like the application object (well it will, but it won't be the same one). Deployment is only slightly harder: deploy the same binaries, but only include the one web service file.

You can authenticate using an HttpModule.
SSL + BasicAuthentication should yield the best interop with other tool chains.
In the HttpModule, you have access to the request and can deny unauthenticated users access to just .asmx requests. And even then you might let them access the WSDL.

Add <add path="*.asmx" verb="*" type="System.Web.HttpForbiddenHandler" validate="True" /> to the <httpHandlers> section of the web.config file

Related

Does the Navision (2009) Webservice support authentication to a remote database?

I'm currently attempting to deploy the Navision webservice (from Dynamics Navision 2009) and am finding that the webservice authenticates when connecting to a local Navision SQL database but NOT a remote Navision SQL database.
So we have servers S (with a full Navision install) and W (with only the Services installed). The CustomSettings.config file on these two systems is identical except that where S references localhost:
<add key="DatabaseServer" value="127.0.0.1"></add>
<add key="ClientCredentialType" value="Windows"></add>
W references S:
<add key="DatabaseServer" value="S"></add>
<add key="ClientCredentialType" value="Windows"></add>
(Other details omitted.) The webservice itself is running as the same domain user in both cases, and that user is authenticated within Navision.
When I connect to the webservice which is running on S, authentication works and the service proceeds as normal:
http://S:7047/DynamicsNAV/WS/Company/Codeunit/RLIntegartion
I'll omit the actual result here. When connecting via W instead:
http://W:7047/DynamicsNAV/WS/Company/Codeunit/RLIntegartion
the webservice instead returns XML indicating an authentication failure:
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<s:Fault>
<faultcode xmlns:a="urn:microsoft-dynamics-schemas/error">
a:Microsoft.Dynamics.Nav.Types.NavDatabasePasswordException
</faultcode>
<faultstring xml:lang="en-US">
The login failed when connecting to SQL Server S.
</faultstring>
<detail>
<string xmlns="http://schemas.microsoft.com/2003/10/Serialization/">
The login failed when connecting to SQL Server S.
</string>
</detail>
</s:Fault>
</s:Body>
</s:Envelope>
I can configure an ODBC connection on W to the Navision database on S and the connection succeeds and authenticates correctly, so the actual database connection and authentication appears to be fine.
I'm aware that the webservice itself must normally be accessed locally so that any files written can be read from where the Navision webservice has written them, but from what I can tell in the documentation the webservice may legitimately access the database from a separate server. However, in practice (per above) this doesn't seem to actually work.
Is this a restriction that Navision imposes? If not, does anyone have any suggestions as to why the webservice is failing to authenticate when accessing a remote database when the same webservice succeeds locally?
Or could it be a limitation imposed by the codeunit programmers? I've spoken to them and they indicate that this should work, but clearly it does not.
That is known problem of Nav 2009. In later versions it's working without additional tricks. To solve this you need to create SPN.
Me personally was not able to set it properly so I just always installed web service tier on the same server with SQL. In this case it works.
There are three participants in this scheme - DB, web service and the client (that connects to this service). The problem appears only when all these three participants are on three different machines.
This three-machine setup will work only if the following requirements are fulfilled:
1) your client is capable of using Kerberos authentication (e.g. Internet Explorer or .NET applications are capable, but Chrome or PHP applications are not)
2) you set up NAV to use Kerberos authentication (as opposed to NTLM) and you set up delegation.
Delegation is a process that allows NAV server (or web service) to take the authentication ticket that came from client and pass it to SQL Server. You need to explicitly allow this in Active Directory setup. For that you will need SPNs - they basically describe the subjects that take part in this delegation.
You may refer to these manuals to setup the whole thing:
MSDN Walkthrough: Installing the Three Tiers on Three Computers
MSDN How to: Configure Web Services with Delegation
NAV 2009 Web Services on a three machine setup
You can also revert to more simple setup of using two-machines setup. In this case, either NAV server and SQL server should be on the same machine, or NAV server and the web service client should be on the same machine. As an example of the latter, you may create a small custom web service which acts as a proxy for your calls, and publish it on the same machine as NAV server/web service.

calling user management services on WSO2 Identity Server

I am looking at two WSO2 client samples that call the user management web service. The first is a simple client, the second is a web app.
The first client sets the system SSL properties and then instantiates a WSUserStoreManager object.
The second one, the web app, does not set SSL properties at all, and instead instantiates a RemoteUserStoreManagerServiceStub.
Could someone please explain why these differences? What service to call when two similar are available (a regular and a 'remote' one)? Isn't it always necessary to set up the SSL properties when calling a https endpoint? Thanks.
if you are calling to HTTPS end point, you need to set the SSL trust store properties to trust the server. But it is under control of the client, If client wants, it can trust it, if not it can ignore. If you want to ignore, you want to override default TrustManager of java.
However, normally java has a trust store file called "cacerts" where it contains all trusted CA certificate. But WSO2IS server's certificate is a self signed one and java can not trust it. Therefore, if you want, you can import certificate in to the "cacerts file. I am not sure about why there are two different in client and web app. However, if you are calling HTTPS, trust must be created. Please check web app source more. Some time, it may have ignore the trust. As web app is run in a app server, sometime java SSL trust properties may have been set to correct file.

The HTTP request is unauthorized with client authentication scheme 'Ntlm'. The authentication header received from the server was 'NTLM'

I am trying to program a VisualWebPart using Visual Studio 2010 which has to do a simple thing: invoke a web service (hosted in a remote server, NOT locally). When I execute within the Sharepoint site (version 2010, which I have published in my IIS) I get this error:
"The HTTP request is unauthorized with client authentication scheme 'Ntlm'. The authentication header received from the server was 'NTLM'."
Pardon my ignorance, but the only difference here is the case of the Ntlm authentication scheme! I have been all over the web and found many related problems, but none of the solutions worked. Almost ALL solutions i found involve modifications in the webservice security configuration, this is not an option for me.
Looking for a solution, I created a sample windows form and invoked the web service from it: no problems whatsoever.
In order to be able to invoke the webservice correctly this is the necessary security configuration:
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Ntlm" proxyCredentialType="Ntlm" realm="" />
<message clientCredentialType="UserName" algorithmSuite="Default" />
</security>
I believe the problem is that I havenĀ“t been able to properly set this security property to the web.config of my Sharepoint site, since I tried to put it in the security tag that appears in the web.config but still get the same error.
Any further information needed please ask, I am REALLY desperate, for days I have been with the SAME error.
In the end I was given permissions in their server: more precisely in the database which was the one that wouldn't let me create the web part in the server. Once this was done, the call to the webservice worked just fine, because they have the web.config correctly configured.

Webservice: Design and Security considerations to take into account?

What design patterns must be evaluated while implementing a web service?
More importantly, what security aspects must be taken into account for a web service? Since a WSDL contains the complete information of the service including the input, output formats and access url, doesn't security get compromised with web service?
Thanks in advance,
Edit
Would just like to add a couple of things.
I am developing the service in Java that would be deployed on a JBoss server hosted on a Linux (Fedora) machine.
As far as authentication mechanism is considered for invoking the services, yes I do have that in place. Unless the user gets a token, he would not be able to use the other services which actually perform the business operation.
Also, have hidden the actual request in 2 layers of XML using CDATA for the actual request body inside the SOAP Envelope body. Something like the below code.
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:myns="http://testserver/testservice">
<soapenv:Header/>
<soapenv:Body>
<myns:Operation>
<myns:OperationRequestBody><![CDATA[-- actual request XML goes here --]]></myns:OperationRequestBody>
</myns:Operation>
</soapenv:Body>
</soapenv:Envelope>
Is there any security aspect for URL - say using HTTPS protocol, which I understand would be a configuration at the server level.
well it depends on number of things:
whether you are exposing your webservice inside the organization (where you dont have to worry much about security) as opposed to exposing the webservice externally.
one thing we do (when we expose internally), we use Windows/NTLM authentication so that specific people in our domain can run it.
I would make sure i dont expose anything that can crush the web service :) (like GetAllData or smth similar) so that you expose only methods that is stateless and easy to throttle if needed.
also, used confluence's API (based on webservice), and they used Authentication mechanism, where you logon first, and you are given token, and you have to attach that token on every web service call that you do.

Silverlight 4.0: Cross Domain Policy Error

I have a webservice and a Silverlight application.
I also have a crossdomain.xml and clientaccesspolicy.xml
<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>
here my cross domain policy
<?xml version="1.0"?>
<!DOCTYPE cross-domain-policy
SYSTEM "http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd">
<cross-domain-policy>
<allow-access-from domain="http://localhost/MHVWS/MachineHistoryWS.asmx" />
</cross-domain-policy>
My web service is being hosted in IIS.
With this configuration I still have this kind of error:
An error occurred while trying to make a request to URI 'http://localhost/MHVWS/MachineHistoryWS.asmx'. This could be due to attempting to access a service in a cross-domain way without a proper cross-domain policy in place, or a policy that is unsuitable for SOAP services. You may need to contact the owner of the service to publish a cross-domain policy file and to ensure it allows SOAP-related HTTP headers to be sent. This error may also be caused by using internal types in the web service proxy without using the InternalsVisibleToAttribute attribute. Please see the inner exception for more details.
Please help
You only need one policy file. You dont require both.
Be sure one (or both) of those policy files exist in the same location (domain) as the webservice.
To debug and see what is going on, use a tool like Fiddler to verify the url path of the policy xml file the client is looking for.