WCF Note2(WCF Security) - Implementation

http://msdn.microsoft.com/library/ff405740.aspx

Here is 3 questions you may ask about the Security:

  • Can any client call the service or do you want to control who can call the service?
  • Can any client call any method of the service or do you want to control what clients can call what methods?
  • Can any client execute all of the code in a method or do you want to control what clients can execute what code?
Scenarios
  • Internal Self-Hosted Services. You are self-hosting a WCF service on the corporate network. You want anyone who can log onto the network to be able to access the service. You want only certain users to be able to call particular methods.
  • Internal Web-Hosted Services. You are hosting a WCF service using Internet Information Services on the corporate intranet. Both employees and guests have access to the wireless network. You want only employees to be able to call the service. You want only certain users to be able to call particular methods.
  • Public Web-Hosted Services. You are hosting a WCF service publicly on the Internet. You want to limit access to the service to users with a valid user name and password. You want only certain users to be able to call particular methods.
Core Concept

 Authentication enables you to identify clients that call the service.  Clients can identify themselves by providing evidence such as a Windows account, a user name / password or a certificate.

 Authorization enables you to determine what operations authenticated clients can access. You will typically base authorization on roles.

Transport Security and Message Security

If you use transport security, security occurs at the transport level. The packets sent “on the wire” include the caller’s credentials and the message. Both of which are encrypted using whatever mechanism the transport protocol uses. For example, if you use TCP, you will likely use Transport Layer Security (TLS) and if you use HTTPS, you will likely use Secure Sockets Layer (SSL).

If you use message security, the caller’s credentials are included in the message and the message is encrypted using the WS-Security specification.

It is generally faster to encrypt and decrypt messages that use transport security and you can benefit from hardware acceleration to improve performance.

A downside to transport security is that messages are encrypted only from point to point. Suppose a client sends a message to a service. The client encrypts the message and the service decrypts it. If the service then forwards the message to another service, the service forwarding the message will not automatically encrypt it. This is not an issue with message security because the service will encrypt the message before passing it on to another service.

A downside to message security is that it requires both clients and services to support the WS-Security specification. Transport security does not have this requirement and is therefore more interoperable.

Configure Security

WCF supports the following six security modes:

  • None. Messages are not secured.
  • Transport. Messages are secured using transport security. 
  • Message. Messages are secured using message security. 
  • TransportWithMessageCredential. Message protection and authorization occur at the transport level and credentials are passed with the message. 
  • TransportCredentialOnly. Credentials are passed at the transport level but the message is not encrypted. This option is available only if you are using the BasicHttpBinding binding.
  • Both. Messages are secured using both transport level and message level security. This is supported only if you are using Microsoft Message Queue Server.

Each binding has a default set of security settings. By default, the following bindings use message security: WSHttpBinding, WS2007HttpBinding, WSDualHttpBinding, WSFederationBinding and WS2007FederationBinding.

By default, the following bindings use transport security: NetTcpBinding, NetNamedPipesBinding, NetMsmqBinding, NePeerBinding and MsmqIntegrationBinding.

By defaultthe BasicHttpBinding binding uses None as its security mode. In other words, message sent using that binding are not secure. This enables interoperability with ASMX Web services.

Authenticate Clients and Services

Authentication enables you to identify clients and services. They identify themselves by passing credentials. WCF supports the following credential types when you are using transport level security:

  • Windows. The client uses a Windows token representing the logged in user’s Windows identity. The service uses the credentials of the process identity or an SSL certificate. 
  • Basic. The client passes a user name and password to the service. Typically, the user will enter the user name and password in a login dialog box. The service uses a SSL certificate. This option is available only with HTTP protocols. 
  • Certificate. The client uses an X.509 certificate and the service uses either that certificate or an SSL certificate.
  • NTLM. The service validates the client using a challenge/response scheme against Windows accounts. The service uses a SSL certificate. This option is available only with HTTP protocols.
  • None. The service does not validate the client.

WCF supports the following credential types when you are using message level security:

  • Windows. The client uses a Windows token representing the logged in user’s Windows identity. The service uses the credentials of the process identity or an SSL certificate. 
  • UserName. The client passes a user name and password to the service. Typically, the user will enter the user name and password in a login dialog box. The service can validate the user name and password using a Windows account or the ASP.NET membership provider. 
  • Certificate. The client uses an X.509 certificate and the service uses either that certificate or an SSL certificate.
  • IssueToken. The client and service use the Secure Token Service, which issues tokens the client and service trust. Windows CardSpace uses the Secure Token Service.
  • None. The service does not validate the client.
Authorize Clients

Authorization enables you to determine what operations authenticated clients can access. WCF supports three basic approaches to authorization:

  • Role-based. Access to a service and to operations of the service is based on the user’s role. 
  • Identity based. Access is based on claims made within the user’s credentials. This is an extension to role-based authorization and provides a more fine grained approach. This approach will typically be used with issue token authentication.
  • Resource based. Resources, such as WCF services, are secured using Windows Access Control Lists (ACLs).

You have three options when deciding how to determine a user’s role:

  • Windows groups. You can use the built-in Windows groups such as Administrators or Power Users or create your own Windows groups. 
  • Custom roles. You can create roles that are specific to your application, such as Manager, Employee, Administrator, etc.
  • ASP.NET role management. You can use the ASP.NET role provider and use roles you have defined for a Web site. 
Sample 1 (WCF Service Host at console app)

Client Config

 <bindings>
      <netTcpBinding>
...
  <security mode="Transport">
            <transport clientCredentialType="Windows" protectionLevel="EncryptAndSign" />
            <message clientCredentialType="Windows" />
          </security>
        </binding>
      </netTcpBinding>
<wsHttpBinding>
<security mode="Message">
            <transport clientCredentialType="Windows" proxyCredentialType="None"
                realm="" />
            <message clientCredentialType="Windows" negotiateServiceCredential="true"
                algorithmSuite="Default" establishSecurityContext="true" />
          </security>
        </binding>
      </wsHttpBinding>
    </bindings>


Server: Authentication

public string SayHello()

{

  return string.Format("Hello {0}",

    System.Threading.Thread.CurrentPrincipal.Identity.Name);

}

Server: Authorization
[PrincipalPermission(SecurityAction.Demand, Role="BUILTIN\\BackupOperators")]
    public decimal ReportSales()
OR

 public decimal ReportSales()
    {
        var currentUser = new WindowsPrincipal((WindowsIdentity)

      System.Threading.Thread.CurrentPrincipal.Identity);

        if (currentUser.IsInRole(WindowsBuiltInRole.BackupOperator))
        {

            return 10000M;

        }

        else
        {
 
            return -1M;

        }
    }

Sample 2 Private Web-Hosted Services (basic authentication)

(WCF Service Host at IIS)

2.1 basic authentication

**When you create the Web site to host the WCF service, you will use HTTPS and SSL to encrypt communications. SSL requires a digital certificate, so you must next create and specify a certificate to use.

How to turn on basic authentication at IIS: http://msdn.microsoft.com/library/ff406125.aspx

How to add a certificate: http://msdn.microsoft.com/library/ff406125.aspx

Client Code

Double-click the Log in button and add the following code to the logInButton_Click method:

// C#

proxy = new SecureServiceClient("WSHttpBinding_ISecureService");

proxy.ClientCredentials.UserName.UserName = nameTextBox.Text;

proxy.ClientCredentials.UserName.Password = passwordTextBox.Text;
Client Configuration
 <bindings>
            <wsHttpBinding>
...
<security mode="Transport">
                        <transport clientCredentialType="Basic" proxyCredentialType="None"
                            realm="" />
                        <message clientCredentialType="Windows" negotiateServiceCredential="true" />
                    </security>
                </binding>
            </wsHttpBinding>
        </bindings>

Sample 3 Public Web-Hosted Services

Server Side Configuration

<?xml version="1.0"?>
<configuration>
	<connectionStrings>
		<add name="ApplicationServices" connectionString="data source=.\SQLEXPRESS;;User ID=sa;Password=password;;initial catalog=aspnetdb;" providerName="System.Data.SqlClient"/>
	</connectionStrings>
	<system.web>
		<!--<authorization>
      <deny users="?" />
    </authorization>-->

    
		<roleManager enabled="true">
			<providers>
				<clear/>
				<add name="AspNetSqlRoleProvider" type="System.Web.Security.SqlRoleProvider" connectionStringName="ApplicationServices" applicationName="/"/>
				<add name="AspNetWindowsTokenRoleProvider" type="System.Web.Security.WindowsTokenRoleProvider" applicationName="/"/>
			</providers>
		</roleManager>
		<authentication mode="Forms"/>
		<membership>
			<providers>
				<clear/>
				<add name="AspNetSqlMembershipProvider" 
             type="System.Web.Security.SqlMembershipProvider" 
             connectionStringName="ApplicationServices" enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="false" requiresUniqueEmail="false" maxInvalidPasswordAttempts="5" minRequiredPasswordLength="6" minRequiredNonalphanumericCharacters="0" passwordAttemptWindow="10" applicationName="/"/>
			</providers>
		</membership>
		<compilation debug="true" strict="false" explicit="true">
			<assemblies>
				<add assembly="System.ServiceModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/></assemblies></compilation>
	</system.web>
	<system.serviceModel>
		<bindings>
			<wsHttpBinding>
				<binding name="WsHttpBindingConfig">
					<security mode="TransportWithMessageCredential">
						<transport clientCredentialType="None"/>
						<message clientCredentialType="UserName" negotiateServiceCredential="false"
                                  establishSecurityContext="false"/>
					</security>
          
				</binding>
			</wsHttpBinding>
		</bindings>
		<services>
			<service name="SecureServiceLibrary.SecureService" behaviorConfiguration="ServiceBehavior">
				<endpoint address="" binding="wsHttpBinding" 
                  bindingConfiguration="WsHttpBindingConfig" 
                  contract="SecureServiceLibrary.ISecureService">
					<identity>
						<dns value="localhost"/>
					</identity>
				</endpoint>
				<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" name="MexHttpsBindingEndpoint"/>
			</service>
		</services>
		<behaviors>
      
			<serviceBehaviors>
     
        <behavior name="ServiceBehavior">
          <serviceMetadata httpGetEnabled="true"/>
					<serviceDebug includeExceptionDetailInFaults="true"/>
					<serviceCredentials>
						<userNameAuthentication 
              userNamePasswordValidationMode="MembershipProvider" 
              membershipProviderName="AspNetSqlMembershipProvider"/>
					</serviceCredentials>
					<serviceAuthorization principalPermissionMode="UseAspNetRoles" roleProviderName="AspNetSqlRoleProvider"/>
				</behavior>
			</serviceBehaviors>
		</behaviors>
		<serviceHostingEnvironment multipleSiteBindingsEnabled="true"/>
	</system.serviceModel>
	<system.webServer>
		<modules runAllManagedModulesForAllRequests="true"/>
	</system.webServer>
	<system.diagnostics>
		<sources>
			<source name="System.ServiceModel" switchValue="Information, ActivityTracing" propagateActivity="true">
				<listeners>
					<add name="traceListener" type="System.Diagnostics.XmlWriterTraceListener" initializeData="c:\log\Traces.svclog"/>
				</listeners>
			</source>
		</sources>
		<trace autoflush="true"/>
	</system.diagnostics>
</configuration>

Client Side Configuration

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <system.serviceModel>
        <bindings>
            <wsHttpBinding>
                <binding name="WSHttpBinding_ISecureService" closeTimeout="00:01:00"
                    openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
                    bypassProxyOnLocal="false" transactionFlow="false" hostNameComparisonMode="StrongWildcard"
                    maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
                    messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true"
                    allowCookies="false">
                    <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
                        maxBytesPerRead="4096" maxNameTableCharCount="16384" />
                    <reliableSession ordered="true" inactivityTimeout="00:10:00"
                        enabled="false" />
                    <security mode="TransportWithMessageCredential">
                      <transport clientCredentialType="None"/>
                      <message clientCredentialType="UserName" negotiateServiceCredential="false"
                                            establishSecurityContext="false"/>
                    </security>
                </binding>
            </wsHttpBinding>
        </bindings>
        <client>
            <endpoint address="https://[yourservername]/PublicWebHostedServiceDemo2/SecureService.svc"
                binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_ISecureService"
                contract="SecureService.ISecureService" name="WSHttpBinding_ISecureService">
                <identity>
                    <dns value="localhost" />
                </identity>
            </endpoint>
        </client>
    </system.serviceModel>
</configuration>

Sample 4 (Certificate) Security Mode="Message"
Server Side Configuration
<?xml version="1.0"?>
<configuration>
	<connectionStrings>
		<add name="ApplicationServices" connectionString="data source=.\SQLEXPRESS;;User ID=sa;Password=password;;initial catalog=aspnetdb;" providerName="System.Data.SqlClient"/>
	</connectionStrings>
	<system.web>
		<authorization>
      <deny users="?" />
    </authorization>
		<roleManager enabled="true">
			<providers>
				<clear/>
				<add name="AspNetSqlRoleProvider" type="System.Web.Security.SqlRoleProvider" connectionStringName="ApplicationServices" applicationName="/"/>
				<add name="AspNetWindowsTokenRoleProvider" type="System.Web.Security.WindowsTokenRoleProvider" applicationName="/"/>
			</providers>
		</roleManager>
		<authentication mode="Forms"/>
		<membership>
			<providers>
				<clear/>
				<add name="AspNetSqlMembershipProvider" 
             type="System.Web.Security.SqlMembershipProvider" 
             connectionStringName="ApplicationServices" enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="false" requiresUniqueEmail="false" maxInvalidPasswordAttempts="5" minRequiredPasswordLength="6" minRequiredNonalphanumericCharacters="0" passwordAttemptWindow="10" applicationName="/"/>
			</providers>
		</membership>
		<compilation debug="true" strict="false" explicit="true">
			<assemblies>
				<add assembly="System.ServiceModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/></assemblies></compilation>
	</system.web>
	<system.serviceModel>
		<bindings>
			<wsHttpBinding>
				<binding name="WsHttpBindingConfig">
					<!--<security mode="TransportWithMessageCredential">
						<transport clientCredentialType="None"/>
						<message clientCredentialType="UserName" negotiateServiceCredential="false"
                                  establishSecurityContext="false"/>
					</security>-->
          <security mode="Message">
            <message clientCredentialType="UserName"  negotiateServiceCredential="true"/>
          </security>
				</binding>
			</wsHttpBinding>
		</bindings>
		<services>
			<service name="SecureServiceLibrary.SecureService" behaviorConfiguration="ServiceBehavior">
				<endpoint address="" binding="wsHttpBinding" 
                  bindingConfiguration="WsHttpBindingConfig" 
                  contract="SecureServiceLibrary.ISecureService">
					<identity>
						<dns value="localhost"/>
					</identity>
				</endpoint>
				<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" name="MexHttpsBindingEndpoint"/>
			</service>
		</services>
		<behaviors>
      
			<serviceBehaviors>
     
        <behavior name="ServiceBehavior">
          <serviceMetadata httpGetEnabled="true"/>
					<serviceDebug includeExceptionDetailInFaults="true"/>
					<serviceCredentials>
            <serviceCertificate findValue="localhost" x509FindType="FindBySubjectName"
                              storeLocation="LocalMachine" storeName="My" />
						<userNameAuthentication 
              userNamePasswordValidationMode="MembershipProvider" 
              membershipProviderName="AspNetSqlMembershipProvider"/>
					</serviceCredentials>
					<serviceAuthorization principalPermissionMode="UseAspNetRoles" roleProviderName="AspNetSqlRoleProvider"/>
				</behavior>
			</serviceBehaviors>
		</behaviors>
		<serviceHostingEnvironment multipleSiteBindingsEnabled="true"/>
	</system.serviceModel>
	<system.webServer>
		<modules runAllManagedModulesForAllRequests="true"/>
	</system.webServer>
	<system.diagnostics>
		<sources>
			<source name="System.ServiceModel" switchValue="Information, ActivityTracing" propagateActivity="true">
				<listeners>
					<add name="traceListener" type="System.Diagnostics.XmlWriterTraceListener" initializeData="c:\log\Traces.svclog"/>
				</listeners>
			</source>
		</sources>
		<trace autoflush="true"/>
	</system.diagnostics>
</configuration>

Client Side Configuration:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <system.serviceModel>
        <bindings>
            <wsHttpBinding>
                <binding name="WSHttpBinding_ISecureService" closeTimeout="00:01:00"
                    openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
                    bypassProxyOnLocal="false" transactionFlow="false" hostNameComparisonMode="StrongWildcard"
                    maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
                    messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true"
                    allowCookies="false">
                    <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
                        maxBytesPerRead="4096" maxNameTableCharCount="16384" />
                    <reliableSession ordered="true" inactivityTimeout="00:10:00"
                        enabled="false" />
                    <security mode="Message">
                        <transport realm="" />
                        <message clientCredentialType="UserName" negotiateServiceCredential="true"/>
                    </security>
                </binding>
            </wsHttpBinding>
        </bindings>
        <client>
            <endpoint address="http://[YourServerName]/PublicWebHostedServiceDemo2/SecureService.svc"
                binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_ISecureService"
                contract="SecureService.ISecureService" name="WSHttpBinding_ISecureService"
                     behaviorConfiguration="certForClient">
                <identity>
                    <dns value="localhost" />
                </identity>
            </endpoint>
        </client>
      <behaviors>
        <endpointBehaviors>
          <behavior name="certForClient">
            <clientCredentials>
              <serviceCertificate >
                <authentication certificateValidationMode="PeerOrChainTrust" revocationMode="NoCheck"/>
              </serviceCertificate>
              <clientCertificate findValue="localhost" x509FindType="FindBySubjectName"
                                          storeLocation="CurrentUser" storeName="My"/>
            </clientCredentials>
          </behavior>
        </endpointBehaviors>
      </behaviors>
    </system.serviceModel>
</configuration>


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值