Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Mike Lewis on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

How to call Web Services using SSL (https://)

Web Services

How to call Web Services using SSL (https://)

by  Glowworm27  Posted    (Edited  )
I wrote this FAQ to help others who may be having the same trouble I have had trying to get my Web Service to work over SSL.

Microsoft has the basics down, but their documentation left out a few important pieces of info.

The URL to setup SSL, and set the Web Service to only work via SSL is clearly documented here. http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnnetsec/html/SecNetHT14.asp

However following along and creating the web service, and the client app to call the web service are missing a few things.

Turns out since .Net 1.0 sp2, and .Net 1.1 in order to call a web service via SSL you must add the web reference using the server name assigned in the Certificate, and not Localhost. This was just one stumbling block to over come.

So I made the necessary change to my web reference, but the client app still cannot call the web service via SSL.

So after some searching on websites here and far, I located this little nugget from KBAlerts. As it turns out when I tried to call the Web Service I would receive this error message "System.Net.WebException. The Underlying Connection Was Closed. Could Not Establish Trust Relationship with Remote Server."
and this page on KBAlerts has the solution the URL is here
http://www.kbalertz.com/kb_823177.aspx

the workaround is easy to implement in the client app. you simply create a little class, and call the class before making the call to the web service. here is code from kbAlerts
VB.Net Code
Code:
Import the following two namespaces, and then implement the class:Imports System.Net
Imports System.Security.Cryptography.X509Certificates
Public Class MyPolicy
  Implements ICertificatePolicy

  Public Function CheckValidationResult(ByVal srvPoint As ServicePoint, _
                ByVal cert As X509Certificate, ByVal request As WebRequest, _
                ByVal certificateProblem As Integer) _
            As Boolean Implements ICertificatePolicy.CheckValidationResult
    'Return True to force the certificate to be accepted.
    Return True
  End Function
End Class
the also have a C# version of this class.

once the class is created implement it in your code before you call the web service. Again the code from the KbAlerts

Code:
System.Net.ServicePointManager.CertificatePolicy = New MyPolicy()

and bingo you should be able to call the web service now.
The reason this workaround works, is when you connect to the web service via a browser you are presented with a Trust Certificate dialog box, asking you if you want to accept the security certificate. Well you can't expect the web service to click the Accept button on the dialog box, so you need to tell it via the class to return a true value whenever you are presented with the Trust Certificate dialog box

well for me that didn't work either. Again something not covered to well by Microsoft, or at least I couldn't locate the answer on their site.

My problem was I am not allowing Anonymous users access to the app or the web service, I unchecked Allow Anonymous Access, and only allow Integrated Windows Authentication.

So the error that I was receiving now was an Access denied error.
Solution thanks to Visual Studio Magazine Vol 12, No.11 Special Issue on Web Services, an Article called "Controlling Access to Web Services" showed me the solution to my problem.

The Client app needed to pass my credentials to the web service, to do this you need to add the namespace System.net to your app, and again before you call the webservice you need to set the Webservice.Credentials = CredentialCache.DefaultCredentials, you also need to setup the web.config file to impersonate identity = true, and set Authentication Mode to "Windows" like this
Code:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <configSections>
    <section name="microsoft.web.services2" type="Microsoft.Web.Services2.Configuration.WebServicesConfiguration, Microsoft.Web.Services2, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
  </configSections>
  <system.web>
<compilation defaultLanguage="vb" debug="true" />
<customErrors mode="RemoteOnly" />
<authentication mode="Windows" />
<identity impersonate="true"/>
 <authorization>
<allow users="*" />
<deny users="?" />
</authorization>
</system.web>
</configuration>

here is my code in my client
Code:
Imports Client.webservice
Imports System.IO
Imports System.Net

Protected Shared wsclient As ODPService

#Region " Web Form Designer Generated Code "

    'This call is required by the Web Form Designer.
    <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()

    End Sub

    '************************************************************************
    'This method initializes the page
    '************************************************************************
    Private Sub Page_Init(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Init
        'CODEGEN: This method call is required by the Web Form Designer
        'Do not modify it using the code editor.
        InitializeComponent()
        'Create the Web Service proxy instance
        wsclient = New ODPService
    End Sub

#End Region

    Dim AsyncWEBServiceProxy As ODPService
    Dim AsyncResult As IAsyncResult


    '************************************************************************
    'This method is called every time the page is loaded
    '************************************************************************
    Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Try
            System.Net.ServicePointManager.CertificatePolicy = New Cert
            wsclient.Credentials = CredentialCache.DefaultCredentials

            'Check if the database connection is alive
            connected = wsclient.isConnected()
'page cut off for brevity

Notice that I call the class Cert to pass a True to the web service so that I can use it via SSL, then I set the Webservice credentials, to my defaultcredentials, now the app, can call the web service via SSL, and as the windows authenticated user.

I hope this little FAQ help someone in the future.
Cheers
George

Register to rate this FAQ  : BAD 1 2 3 4 5 6 7 8 9 10 GOOD
Please Note: 1 is Bad, 10 is Good :-)

Part and Inventory Search

Back
Top