views:

1096

answers:

3

Hi all,

I've a created a simple WCF REST service which I intend to consume from an iPhone application. The service works fine but now I'd like to secure it.

In my test enviornment (IIS on Windows 7) I already setup a self signed certificate using makecert.exe.

I also overridden the validate() method so I can use a custom username & password (since windows authentication is out of the question).

Now I'm stuck for more than two days figuring out how to configure everything so it can work.

My goal now is to be able to do a simple GET request via the browser, something like:

https://localhost/testservice/service1.svc/sayHello

When this will work I'll continue on to all iPhone related stuff.

Any help / examples will be highly appreciated!

Here's my web.config:

 <system.serviceModel>
<services>
  <service name="IphoneWcf.Service1" behaviorConfiguration="IphoneWcf.Service1Behavior">
    <!-- Service Endpoints -->
    <endpoint address="" binding="basicHttpBinding" bindingConfiguration="webBinding" behaviorConfiguration="webBehavior" contract="IphoneWcf.IService1">
      <!-- 
          Upon deployment, the following identity element should be removed or replaced to reflect the 
          identity under which the deployed service runs.  If removed, WCF will infer an appropriate identity 
          automatically.
      -->
      <identity>
        <dns value="localhost" />
      </identity>
    </endpoint>
    <!--<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/> -->
    <host>
      <baseAddresses>
        <add baseAddress="https://localhost/iphonewcf" />
      </baseAddresses> 
     </host>
  </service>
</services>
<behaviors>
  <endpointBehaviors>
    <behavior name="webBehavior">

    </behavior>
     </endpointBehaviors>
  <serviceBehaviors>
    <behavior name="IphoneWcf.Service1Behavior">
      <!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
      <serviceMetadata httpsGetEnabled="false" />
      <!-- 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="localhost" storeLocation="LocalMachine" storeName="My" x509FindType="FindBySubjectName" />
      </serviceCredentials>
    </behavior>
  </serviceBehaviors>
</behaviors>
<bindings>
  <basicHttpBinding>
    <binding name="webBinding">
      <security mode="Transport">
        <transport clientCredentialType="Basic" />
      </security>
   </binding>
  </basicHttpBinding>
</bindings>

Thanks in advance!

A: 

You shouldn't have to override any method. Just declare Digest transport security in your basicHttpBinding:

<bindings>
  <basicHttpBinding>
    <binding name="SecurityByTransport">
      <security mode="Transport">
        <transport clientCredentialType="Digest" />
       </security>
     </binding>
  </basicHttpBinding>
</bindings>

In you iPhone app you handle the NSURLConnectionDelegate connection:didReceiveAuthenticationChallenge message as shown in Handling Authentication Challenges:

-(void)connection:(NSURLConnection *)connection 
        didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge 
{ 
    if ([challenge previousFailureCount] == 0) { 
        NSURLCredential *newCredential; 
        newCredential=[NSURLCredential credentialWithUser:[self preferencesName] 
                                                 password:[self preferencesPassword] 
                                              persistence:NSURLCredentialPersistenceNone]; 
        [[challenge sender] useCredential:newCredential 
               forAuthenticationChallenge:challenge]; 
    } else { 
        [[challenge sender] cancelAuthenticationChallenge:challenge]; 
    } 
}
Remus Rusanu
Almost there..I can't use digest because my test machine is not a part of any domain. So for a start I use basic authentication. After I enter username/password I get an error "resource not found"
zippod
Actually I wasn't aware IIS can only authenticate digest users against a domain directory. I guess I was thinking along the lines of ASP.Net authentication provider http modules, as in http://msdn.microsoft.com/en-us/library/bb386455.aspx. Where do you get the 'resource not found error' ?
Remus Rusanu
When I perform a GET request in Internet explorer for the following URL: https://localhost/testservice/service1.svc/sayHelloI get a prompt asking for username and password. After providing the username and password associated with my Windows account - right there I get the page cannot be found error
zippod
+1  A: 

Another option would be to create another cert for client authentication. I'm pretty sure the iPhone supports X509 certs. Just change your config to have a client credential type of "Certificate". This works for basic authentication, but you may still need custom user/name pwd over Basic if you want to uniquely identify every client.

Adam Fyles
A: 

Hi Zippod,

I am facing same problem. Did you resolved this ? If so, how did you handled this.

Chakris