středa 3. listopadu 2010

WCF a UserNamePasswordValidator

Laboroval jsem teď nějakou chvíli s ověřováním uživatelů ve WCF. Potřeboval jsem kontrolovat, že uživatel volající metody WCF služby, má právo je využívat. Bohužel jsem byl předem omezen mantinely:
  • credentials uživatelů v MS SQL
  • basicHttpBinding
  • služba hostovaná v IISku
Použitý binding je omezující v tom, že komunikace musí být vždy zabezpečená pomocí certifikátu, bez něj to prostě nejde. Zajímavé je, že to nemusí být na IISku definované jako "required". Ale i když jsem definoval referenci služby bez https, tak se generoval endpoint s https. Je to někde "natvrdo" nastavené a bez https to nefunguje.
Jsou asi jen 2 možnosti, jak ověřovat uživatele:
  • využít ASP.NET providera
  • využít třídu UserNamePasswordValidator
Rozdíl je asi jen v komplexnosti, co od toho očekáváte. Výhoda ASP.NET providera je v tom, že lze použít i návazné role a profily. 
Mě stačilo jednoduché ověření uživatele. Také proto, že jsem měl jinou strukturu DB pro uživatele a tím pádem bych musel psát vlastního ASP.NET providera, jsem se rozhodl pro využití UserNamePasswordValidator. Odvodil jsem si vlastní třídu a přepsal metodu Validate - jednoduchý příklad je v MSDN.
Největší problém byl s konfigurací, aby validátor správně fungoval a nepoužívalo se ověřování Windows. Nastavení WCF služby:

<system.serviceModel>
<services>
<service name="ServiceLibrary.Service" behaviorConfiguration="CoopServiceBehavior">
<!-- Service Endpoints -->
                 <endpoint address="" binding="basicHttpBinding" bindingConfiguration="MyBinding" contract="ServiceLibrary.IService"/>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
</services>
<bindings>
<basicHttpBinding>
<binding name="MyBinding">
<security mode="TransportWithMessageCredential">
<message clientCredentialType="UserName" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="CoopServiceBehavior">
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="false"/>
<serviceCredentials>
<serviceCertificate findValue="CN=zeleny5" storeName="CertificateAuthority" x509FindType="FindByIssuerName"/>
<userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="ServiceLibrary.CustomUserNameValidator, ServiceLibrary"/>
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>

Na IISku si vygenerujete certifikát, který by měl být podepsaný nějakou certifikační autoritou (CA). Na klientovi musí být certifikát CA nainstalován mezi důvěryhodnými kořenovými certifikačními úřady. Jinak bude při komunikaci vyvolána chyba. Dále je potřeba na serveru udělit práva na čtení k certifikátu. Na adresáři C:\ProgramData\Microsoft\Crypto\RSA\MachineKeys nastavte práva na čtení pro Network Service, pod kterým běží služba v IISku (nastaveno v aplikačním poolu). Může to hlásit chyby typu Access Denied, ale to nevadí, protože to stejně bude fungovat ;-) Na webu, kde poběží služba, je potřeba definovat vazbu na HTTPS s vygenerovaným a podepsaným certifikátem. Není potřeba nastavovat vyžadování SSL.

Když je vše správně nakonfigurované, tak by to mělo fungovat... klient se připojí ke službě, ta ho ověří a dovolí mu vyvolat požadovanou metodu. V opačném případě dojde k chybě - v závislosti na implementaci v metodě Validate.

Žádné komentáře:

Okomentovat