Connor_Smith14 Connor_Smith14 - 12 days ago 10
Vb.net Question

Single WCF .svc, multiple clients connecting

I have created a WCF Service with multiple Interfaces. This serves multiple users at one time.

Do I need to alter anything in the ServiceContract or ServiceBehaviour to make sure that there's no "crossing" over between two clients?

The ServiceContract is left blank, however the ServiceBehaviour in my .svc is like so:

<ServiceBehavior(InstanceContextMode:=InstanceContextMode.PerCall, AutomaticSessionShutdown:=True,
ConcurrencyMode:=ConcurrencyMode.Single, IncludeExceptionDetailInFaults:=True)>


Any help is greatly appreciated.

Validation:

Imports System.Data.SqlClient
Imports System.IdentityModel.Selectors
Imports System.Reflection
Imports System.Security
Imports System.Threading
Imports DVPWCFService.Modules

Namespace Classes.Admin

Public Class Validation
Inherits UserNamePasswordValidator

Private _dbUsername As String
Private _dbPassword As SecureString

Public Overrides Sub Validate(userName As String, password As String)
Try
_dbUsername = userName
_dbPassword = ConvertToSecureString(password)
DbUsername = userName
DbPassword = ConvertToSecureString(password)

Dim dummyConnectionForValidation As SqlConnection = LogInTry("A real server name")

dummyConnectionForValidation.Close()
dummyConnectionForValidation.Dispose()

Catch ex As Exception

If ex.GetType Is GetType(SqlException) Then
DVPEventLog.WriteEntry("Authentication has failed for user: '" + userName + "'", EventLogEntryType.Warning)
Else
DVPEventLog.WriteEntry("Error: " & ex.Message & Environment.NewLine & Environment.NewLine & "Stack Trace: " & ex.StackTrace & Environment.NewLine & Environment.NewLine & "Method Name: " & MethodBase.GetCurrentMethod.Name, EventLogEntryType.Error, EventLogEntryType.Error)
End If

Thread.Sleep(5000)

Throw New FaultException("Log in failed.")
End Try
End Sub

Private Function LogInTry(serverName As String) As SqlConnection
LogInTry = New SqlConnection
LogInTry.ConnectionString = "Data Source=" & serverName & ";Persist Security Info=True;MultipleActiveResultSets=True;"
LogInTry.FireInfoMessageEventOnUserErrors = True
LogInTry.Credential = New SqlCredential(_dbUsername, _dbPassword)
LogInTry.Open()
End Function

Private Function ConvertToSecureString(convertee As String) As SecureString

ConvertToSecureString = New SecureString()

For Each stringCharacter In convertee.ToCharArray()
ConvertToSecureString.AppendChar(stringCharacter)
Next

ConvertToSecureString.MakeReadOnly()

End Function

End Class
End Namespace


Web Config:

<?xml version="1.0"?>
<configuration>

<appSettings>
<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
</appSettings>
<system.web>
<compilation debug="true" strict="false" explicit="true" targetFramework="4.5.2" />
<httpRuntime targetFramework="4.5.2"/>
</system.web>
<system.serviceModel>
<bindings>

<wsHttpBinding>
<binding name="SSL Binding" openTimeout="00:00:20" receiveTimeout="08:00:00" maxBufferPoolSize="2147483647" maxReceivedMessageSize="2147483647">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="2147483647"
maxBytesPerRead="4096" maxNameTableCharCount="2147483647" />
<security mode="TransportWithMessageCredential">
<transport clientCredentialType="None" />
<message clientCredentialType="UserName" algorithmSuite="TripleDesSha256Rsa15" />
</security>
</binding>
</wsHttpBinding>

</bindings>
<services>

<service behaviorConfiguration="Custom Validation Service Behavior" name="DVPWCFService.DVP">
<endpoint address="" binding="wsHttpBinding" bindingConfiguration="SSL Binding"
name="IComponent" contract="DVPWCFService.Interfaces.IComponent" />
<endpoint address="" binding="wsHttpBinding" bindingConfiguration="SSL Binding"
name="IProgramme" contract="DVPWCFService.Interfaces.IProgramme" />
<endpoint address="" binding="wsHttpBinding" bindingConfiguration="SSL Binding"
name="IVehicle" contract="DVPWCFService.Interfaces.IVehicle" />
<endpoint address="" binding="wsHttpBinding" bindingConfiguration="SSL Binding"
name="IMiscellaneous" contract="DVPWCFService.Interfaces.IMiscellaneous" />
<endpoint address="mex" binding="mexHttpsBinding" name="metadata"
contract="IMetadataExchange" />
<endpoint address="" binding="wsHttpBinding" bindingConfiguration="SSL Binding"
name="IReservation" contract="DVPWCFService.Interfaces.IReservation" />
</service>

</services>
<behaviors>
<serviceBehaviors>

<behavior name="Custom Validation Service Behavior">
<serviceMetadata httpsGetEnabled="true" />
<serviceDebug httpHelpPageEnabled="true" httpsHelpPageEnabled="true"
includeExceptionDetailInFaults="true" />
<serviceCredentials>
<serviceCertificate findValue="blahblahblah"
x509FindType="FindByThumbprint" />
<userNameAuthentication userNamePasswordValidationMode="Custom"
customUserNamePasswordValidatorType="DVPWCFService.Classes.Admin.Validation, DVPWCFService"/>
</serviceCredentials>
<dataContractSerializer />
<serviceThrottling maxConcurrentCalls="10" maxConcurrentSessions="10" maxConcurrentInstances="1" />
</behavior>

</serviceBehaviors>
</behaviors>
<protocolMapping>
<add binding="wsHttpBinding" scheme="https" />
</protocolMapping>
<serviceHostingEnvironment aspNetCompatibilityEnabled="false" multipleSiteBindingsEnabled="false" />
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
<directoryBrowse enabled="false"/>
</system.webServer>

</configuration>

Answer

So after several hours of digging, to force it to authenticate on each call and therefore not intervene with other contexts, I out this in the binding:

<message clientCredentialType="UserName" 
 algorithmSuite="TripleDesSha256Rsa15" 
 establishSecurityContext="false" /> 

The important bit being establishSecurityContext="false", the default for this is true so it remembers the last established log in, when you set it to false, it re-authenticates on each call. For this to be efficient, you'll need your authentication code to be slick.

Comments