2014-03-12 48 views
4

我想從控制檯應用程序發佈WCF服務。爲了安全起見,我希望通過SSL進行通信,因此我創建了一個自簽名證書。對於身份驗證,我編寫了自己的UserNamePasswordValidator。不幸的是,這是不工作使用SSL和用戶名和密碼進行身份驗證的自託管WCF服務

這是到目前爲止我的代碼:

服務器

public class Program 
{ 
    public static void Main() 
    { 
     var baseAddress = new Uri("https://localhost:8080/SelfHostedUsernamePasswordService"); 

     using (var host = new ServiceHost(typeof(SelfHostedUsernamePasswordService), baseAddress)) 
     { 
      var binding = new BasicHttpBinding(BasicHttpSecurityMode.TransportWithMessageCredential); 
      binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic; 
      binding.Security.Message.ClientCredentialType = BasicHttpMessageCredentialType.Certificate; 

      var endpoint = host.AddServiceEndpoint(typeof(ISelfHostedUsernamePasswordService), binding, baseAddress); 

      var cf = new ChannelFactory<ISelfHostedUsernamePasswordService>(binding, endpoint.Address); 
      cf.Credentials.ClientCertificate.SetCertificate(
       StoreLocation.LocalMachine, 
       StoreName.My, 
       X509FindType.FindByThumbprint, 
       "0000000000000000000000000000000000000000"); 

      var metadataBehavior = new ServiceMetadataBehavior(); 
      metadataBehavior.HttpsGetEnabled = true; 
      metadataBehavior.MetadataExporter.PolicyVersion = PolicyVersion.Policy15; 
      host.Description.Behaviors.Add(metadataBehavior); 

      var credentialBehavior = new ServiceCredentials(); 
      credentialBehavior.UserNameAuthentication.CustomUserNamePasswordValidator = new UsernamePasswordValidator(); 
      credentialBehavior.UserNameAuthentication.UserNamePasswordValidationMode = UserNamePasswordValidationMode.Custom; 
      host.Description.Behaviors.Add(credentialBehavior); 

      host.Open(); 

      Console.WriteLine("The service is ready at {0}", baseAddress); 
      Console.WriteLine("Press <Enter> to stop the service."); 
      Console.ReadLine(); 

      host.Close(); 
     } 
    } 
} 

public class UsernamePasswordValidator : UserNamePasswordValidator 
{ 
    public override void Validate(string userName, string password) 
    { 
     if (!string.Equals(userName, "admin", StringComparison.OrdinalIgnoreCase) || 
      !string.Equals(password, "password", StringComparison.Ordinal)) 
     { 
      Console.WriteLine("Validation failed."); 
      throw new SecurityTokenException("Validation failed."); 
     } 
     Console.WriteLine("Validation successful."); 
    } 
} 

客戶

class Program 
{ 
    static void Main() 
    { 
     using (var client = new SelfHostedUsernamePasswordServiceClient()) 
     { 
      client.ClientCredentials.UserName.UserName = "admin"; 
      client.ClientCredentials.UserName.Password = "password"; 

      var result = client.GetData(12345); 
      Console.WriteLine("Result from service: {0}", result); 

      client.Close(); 
     } 
    } 
} 

有了這個代碼,我得到一個MessageSecurityException(找不到System.IdentityModel.Tokens.UserNameSecuri的令牌認證器tyToken'令牌類型)。但我認爲與創建TokenAuthenticator我在錯誤的路徑...

順便說一句,UsernamePasswordValidator永遠不會被調用。

回答

4

好吧,明白了。

我必須將Transport CredentialType設置爲'Certificate'並將Message CredentialType設置爲'UserName'。在雙方。

這是工作代碼:

服務器

public class Program 
{ 
    public static void Main() 
    { 
     var baseAddress = new Uri("https://localhost:8080/SelfHostedUsernamePasswordService"); 

     using (var host = new ServiceHost(typeof(SelfHostedUsernamePasswordService), baseAddress)) 
     { 
      var binding = new BasicHttpBinding(BasicHttpSecurityMode.TransportWithMessageCredential); 
      binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Certificate; 
      binding.Security.Message.ClientCredentialType = BasicHttpMessageCredentialType.UserName; 

      var endpoint = host.AddServiceEndpoint(typeof(ISelfHostedUsernamePasswordService), binding, baseAddress); 

      var cf = new ChannelFactory<ISelfHostedUsernamePasswordService>(binding, endpoint.Address); 
      cf.Credentials.ClientCertificate.SetCertificate(
       StoreLocation.LocalMachine, 
       StoreName.My, 
       X509FindType.FindByThumbprint, 
       "0000000000000000000000000000000000000000"); 

      var credentialBehavior = new ServiceCredentials(); 
      credentialBehavior.UserNameAuthentication.CustomUserNamePasswordValidator = new UsernamePasswordValidator(); 
      credentialBehavior.UserNameAuthentication.UserNamePasswordValidationMode = UserNamePasswordValidationMode.Custom; 
      credentialBehavior.IssuedTokenAuthentication.AllowUntrustedRsaIssuers = true; 
      host.Description.Behaviors.Add(credentialBehavior); 

      var metadataBehavior = new ServiceMetadataBehavior(); 
      metadataBehavior.HttpsGetEnabled = true; 
      metadataBehavior.MetadataExporter.PolicyVersion = PolicyVersion.Policy15; 
      host.Description.Behaviors.Add(metadataBehavior); 

      host.Open(); 

      Console.WriteLine("The service is ready at {0}", baseAddress); 
      Console.WriteLine("Press <Enter> to stop the service."); 
      Console.ReadLine(); 

      host.Close(); 
     } 
    } 
} 

public class UsernamePasswordValidator : UserNamePasswordValidator 
{ 
    public override void Validate(string userName, string password) 
    { 
     if (!string.Equals(userName, "admin", StringComparison.OrdinalIgnoreCase) || 
      !string.Equals(password, "password", StringComparison.Ordinal)) 
     { 
      Console.WriteLine("Validation failed."); 
      throw new SecurityTokenException("Validation failed."); 
     } 
     Console.WriteLine("Validation successful."); 
    } 
} 

客戶

class Program 
{ 
    static void Main() 
    { 
     var remoteAddress = new EndpointAddress(new Uri("https://localhost:8080/SelfHostedUsernamePasswordService")); 

     var binding = new BasicHttpBinding(BasicHttpSecurityMode.TransportWithMessageCredential); 
     binding.Security.Message.ClientCredentialType = BasicHttpMessageCredentialType.UserName; 
     binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Certificate; 

     using (var client = new SelfHostedUsernamePasswordServiceClient(binding, remoteAddress)) 
     { 
      client.ClientCredentials.UserName.UserName = "admin"; 
      client.ClientCredentials.UserName.Password = "password"; 

      var result = client.GetData(12345); 
      Console.WriteLine("Got result from service: {0}", result); 
      Console.ReadLine(); 

      client.Close(); 
     } 
    } 
} 
相關問題