0

I am updating a web service application written in VS2012 in C# in which I would like to get the client application name.

Is there a system calls that I can make to get this value?

Originally, in the web service application had the following line of code:

string ApplicationID = 
       System.ServiceModel.ServiceSecurityContext.Current.PrimaryIdentity.Name;

This .Name value returns the user's name and I need the client application name.

How can I, securely, get the client's application name?

  • UPDATE: It seems like the ClientCredential class can be used to set a user name like:

    service1.ClientCredentials.UserName.UserName = "ClientTestApp";

in the client application and you can access the the user name in the web service application using:

 string TestAppName = System.ServiceModel.ServiceSecurityContext.Current.PrimaryIdentity.Name;

How should the binding for the endpoint be configured?

UPDATE:

To give an example of what I mean in the comment below...

CLIENT APPLICATION:

        Service1.ClientCredentials.UserName.UserName = "ClientAppName";

        try
        {
            Service1.Method1(ProfileID, OrderID);
        }
        catch (Exception ex)
        {
            string Error = ex.Message;
        }

WEB SERVICE METHOD:

 public void Method1(long ProfileID, int OrderID)
    {
        //The ApplicationID will be "ClientAppName"
        string ApplicationID = ServiceSecurityContext.Current.PrimaryIdentity.Name;
        try
        {
            //CHeck the ApplicationID and do stuff...
        }
    }

Configuration File The binding will probably have to include a Credential of UserName. But I can't seem to get the correct configuration to get this to work.

Is what I am describing possible?

UPDATE

I have read a lot about setting the configuration file with these security elements and attributes. But I am still learning. So I apologize, in advance, for asking some basic questions.

I got a value assigned to the ApplicationID in the web service application:

string ApplicationID = ServiceSecurityContext.Current.PrimaryIdentity.Name;

by using this binding configuration:

<wsHttpBinding>
      <binding name="ServiceEndpoint"  closeTimeout="00:01:00">
        <security mode="Message">
        </security> 
      </binding>
</wsHttpBinding>

However, the value stored in

ServiceSecurityContext.Current.PrimaryIdentity.Name;

is my User Name for Windows Authentication in my SQL Server 2012 Management Studio.

According to the documentation the ServiceSecurityContext class should return the following: "Represents the security context of a remote party. On the client, represents the service identity and, on the service, represents the client identity."

How is it getting this user name value?

Is there anyway I can set it with another value?

By using wsHttpBinding and the Message attribute, does this mean it is using the SOAP message security? (The body is encrypted and signed.)

TRYING ANOTHER APPROACH If I set the ClientCredentials.UserName.UserName = "TestClient" ClientCredentials.UserName.Password = "some password" In the client test application.

Add UserNamePasswordValidator class and override the Validate() method. Within this method, it checks a table in a database for the username and password.

My current configuration file with wsHttpBinding is this:

<wsHttpBinding>
  <binding name="PaymentSecureServiceEndpoint"  closeTimeout="00:01:00">
    <security mode="Message">
      <message clientCredentialType="UserName"/>
    </security> 
  </binding>
</wsHttpBinding>

When I try to update the service reference, I get the error: 'The Service certificate is not provided. Specify a service certificate in ServerCredentials.'

Is there any way I can use the validate() method without providing a service certificate? Does the ServerCredentials have to be at the service level, can it be at the endpoint level? Will this set the PrimaryIdentity.Name value to the UserName that I set in the client application?

Thanks...as always.

ADDING SELF-SIGNED CERTIFICATE

The name of my self-signed certificate is: TestCert. The location I put the certificate is: Console Root / Certificates (Local Computer) / Personal / Certificates.

This is the service behavior defined in the web.config file:

 <behavior name="SecureBehavior">
      <serviceCredentials>
        <userNameAuthentication userNamePasswordValidationMode="Custom" 
                                customUserNamePasswordValidatorType="Service1.Service1UsernamePasswordValidator, Service1"/>
        <serviceCertificate findValue="TestCert" storeLocation="LocalMachine" storeName="My" x509FindType="FindBySubjectName"/>
      </serviceCredentials>
    </behavior>

I get the error that it cannot find my x.509 Certificate. What did I do wrong on the serviceCertificate attributes?

UPDATE TO GETTING THE SERVICE CERTIFICATE TO BE ACCEPTED BY THE CLIENT WHEN UPDATING THE SERVICE REFERENCE I still get the error that if cannot find the certificate, even if I trying using the serial number. Below are the details of my errors:

I have a self-signed certificate in the folder of 'Certificates' under the folder 'Personal'. The 'Friendly Name' is 'TestCert'. The serial number is a hexidecimal number that starts ' 7f 79 8a a7...'. The certificate is on my local machine.

The attributes that I have tried:

storeLocation="LocalMachine" - I have not changed this. The certificate is on my local machine and all of the documentation states that when it is, this is the value that it should be.

storeName="My" - The certificate is in the 'Personal' folder in the 'Certificate' folder. This should correspond to 'My'. I guess it would be too intuitive to call it 'Personal'.

x509FindType="FindBySubjectName" - I have kept this value as '..SubjectName' when the 'findValue' was the name of the certificate. The 'Friendly Name' of the certificate is 'TestCert'. There is no option for 'FriendlyName' but I have tried 'By...DistinguishedName', 'By...TemplateName'. I have also set the option to 'FindBySerialNumber'

findValue="" - I have used the certificate name 'TestCert' and 'CN=TestCert' I have a tried copying the serial number and set the x509FindType option to search by SerialNumber but I get the error: 'Invalid hexidecimal string format'.

Why is this so difficult? There is 2 certificates in my Personal folder, one - localhost and one - 'TestCert'. It should not be that difficult to find it.

Is the problem that it is a self-signed certificate? Is it not a x509 certificate? How do I check if it is, it is not in the properties list.

No wonder security is so difficult! The documentation is bad and following the instructions do not work.

Gloria Santin
  • 2,066
  • 3
  • 51
  • 124
  • When you say client application name - are you referring to the application consuming the webeservice or the webservice itself? – warwickf Feb 20 '14 at 17:57
  • Yes. I thought I could set the ClientCredentials in the client application and configure a binding in the web service as a wsHttpBinding and set the security= message. Then the PrimaryIdentity.Name in the web service would be what I set in the client application. But the value I get is my SQL Server doman and my user name. – Gloria Santin Feb 20 '14 at 18:26
  • If I understand correctly you want the consumer's name. Is your client the only one consuming the service? If so, the add it as a parameter on the initial access and send a tracking tracking back to the client... Would that not work? – warwickf Feb 20 '14 at 18:36
  • Currently, I only have a test app. that is connected to the web service. But in production there can be as many as client apps. connected to the web service. I don't want to change the parameter list of the method. – Gloria Santin Feb 20 '14 at 18:41

1 Answers1

1

The reason why I ask is this: The client only consumes the webservice - that means there is no connection between the client and the service apart from the request(s). So either you send the client name via the querystring (encrypted if necessary) or via a session variable (much like a form post), I could be wrong but I don't think one could have a tight link between a client and a webservice like that - it would go against the idea of a webservice being a loosely coupled service.

warwickf
  • 123
  • 6
  • I thought the client application can set the ClientCredentials before a web service method is called. When the method is called the client credentials can be checked within the method. – Gloria Santin Feb 20 '14 at 19:52
  • I added more details to the original post as to what I was hope to do. – Gloria Santin Feb 20 '14 at 20:13
  • The way you are describing means that you want to use active directory - but that would entail that each client has an active windows login. I am not too familiar with this though. If you dont want to use active directory, the easiest way to do what you want is to set a session variable with the encrypted name of the client. You can the use this session variable as a ticket and return nothing if it is not set. – warwickf Feb 21 '14 at 05:37
  • I can now get a value in the PrimaryIdentity.Name field but it is not the client application name which is what I was expecting but my user name. I explain it more completely above in the original post under the last 'UPDATE'. – Gloria Santin Feb 21 '14 at 20:36
  • This is the local (ie the Server's security) not the client's security. If one has a shared authentication pool (like Active Directory) then one could share the authentication between all connected services/servers/PCs. If not then one must go according to the normal rules of HTTP which is a stateless protocol. The only other option is looking at the HTTP headers - that will probably have the client information... To get it is quite tricky, but it is possible. This is where the session information is kept... – warwickf Feb 23 '14 at 13:10
  • I am trying another approach...Can I set the ClientCredentials (Username and Password) in the client application, and use User Name Password Validator to validate them by checking values in a database table without using a service certificate? I added more detail above with config file for a better understanding. – Gloria Santin Feb 24 '14 at 17:17
  • That's a better approach. But WCF will always have to have some sort of security - it is built into it. I found a nice article that describes this and how to fix it: http://blog.functionalfun.net/2008/05/how-to-create-server-certificate-for.html – warwickf Feb 24 '14 at 18:08
  • I tried adding a self-signed certificate to my local machine by following the directions in the blog post. When I try updating my service reference, I get the error that it can't find the X.509 certificate. I put the details above... – Gloria Santin Feb 24 '14 at 19:40
  • Ok, with a quick search I found: http://stackoverflow.com/questions/216109/cannot-find-the-x-509-certificate-using-the-following-search-criteria. It could be something to do with the name, so rather use the serialnumber. – warwickf Feb 25 '14 at 04:33
  • I really appreciate the time, effort and suggestions you have given to help me solve all of the security problems that I have encountered. – Gloria Santin Feb 25 '14 at 13:56
  • I have tried every configuration to get this service to update and nothing is working! Above, I have detailed all my efforts in trying to get this certificate to be accepted by the client but I am still getting the error regarding the service certificate... – Gloria Santin Feb 25 '14 at 13:59
  • Do I have to use certificates if I am NOT using SSL? I just need message level security. The documentation that explains how to create a custom validator for username/password does not mention needed certificates. I am using HTTP protocol. – Gloria Santin Feb 25 '14 at 15:35
  • No you don't. Certificates are only for SSL/TLS on HTTPS. Normal HTTP traffic never uses certificates. Message level security is easier. On a current web service I am doing I send encrypted login information to the web service which returns a guid that has been saved in the DB. Each call to the WS must have this ticket to authenticate otherwise an empty response is returned. One suggestion to handle the security. – warwickf Feb 26 '14 at 04:51
  • Wow. If I could use a custom userNameAuthentication validator only and not have to deal with service certificates, _that_ would be great! It seems to me the documentation and forums are all over the place on this. I defined the binding as wsHttpBinding and message security with a client credential=UserName. The service behavior I defined the userNameAuthentication=custom. When I update the service reference, the error is that it can't find the service certificate. How do I get around **not** using a certificate? – Gloria Santin Feb 26 '14 at 13:20
  • I **FINALLY** got the service to work. I did need to add a service certificate to make this work. If anybody else needs to do this, a great resource to step you thru the process is this: [link](http://msdn.microsoft.com/en-us/library/ff647171.aspx). THANKS FOR ALL OF YOUR HELP @warwickf – Gloria Santin Feb 26 '14 at 18:53