WCF: Cannot find my custom validator specified in web.config - customUserNamePasswordValidatorType - - Could not load file or assembly ... - help?

So, I basically made it all with wsHttpBindings and my WCF service, using my own HTTPS authentication.

The problem I encountered is related to customUserNamePasswordValidatorType:

<serviceCredentials> <!-- Use our own custom validation --> <userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="CustomValidator.CustomUserNameValidator, CustomValidator"/> </serviceCredentials> 

The routes below are here. I also created my own class:

 namespace CustomValidator { public class CustomUserNameValidator : UserNamePasswordValidator { public override void Validate(string userName, string password) { if (null == userName || null == password) { throw new ArgumentNullException(); } if (!AuthenticateUser(userName, password)) throw new SecurityTokenValidationException("Invalid Credentials"); 

The error " Failed to load the file or assembly" CustomValidator "or one of its dependencies. The system cannot find the specified file. " And refers to the endpoint of customUserNamePasswordValidatorType - "..., CustomValidator".

I did not think this was a problem with my custom validator in my own namespace and class, but I do not see what else to do to make this work.

I tried with / without namespace at the beginning, swapping, etc. - nothing.

Hoping another pair of eyes can choose this.

Thanks.

EDIT system.serviceModel

  <system.serviceModel> <bindings> <!-- wsHttpBinding --> <wsHttpBinding> <binding name="wsHttpEndpointBinding"> <security mode="TransportWithMessageCredential"> <transport clientCredentialType="None" /> <message clientCredentialType="UserName" /> </security> </binding> </wsHttpBinding> <!-- webHttpBinding --> <webHttpBinding> <binding name="wsHttps" > <security mode="Transport"/> </binding> </webHttpBinding> <!-- Basic binding --> <basicHttpBinding> <binding name="TransportSecurity"> <security mode="Transport"> <message clientCredentialType="UserName"/> <!-- transport clientCredentialType="None"/--> </security> </binding> </basicHttpBinding> <!-- customBinding> <binding name="WebHttpBinding_IService"> textMessageEncoding maxReadPoolSize="64" maxWritePoolSize="16" messageVersion="Soap12" writeEncoding="utf-8"> <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384" maxBytesPerRead="4096" maxNameTableCharCount="16384" /> </textMessageEncoding> <httpsTransport manualAddressing="false"/> </binding> </customBinding --> <!-- Another custom binding --> <customBinding> <binding name="CustomMapper"> <webMessageEncoding webContentTypeMapperType= "IndexingService.CustomContentTypeMapper, IndexingService" /> <httpTransport manualAddressing="true" /> </binding> </customBinding> </bindings> <serviceHostingEnvironment aspNetCompatibilityEnabled="false" /> <services> <service behaviorConfiguration="ServiceBehavior" name="Service"> <!-- Service Endpoints --> <!-- since we're hosting in IIS, baseAddress is not required <host> <baseAddresses> <add baseAddress="https://mysslserver.com/Service.svc"/> </baseAddresses> </host> --> <endpoint address="https://mysslserver.com/Service.svc" binding="wsHttpBinding" bindingConfiguration="wsHttpEndpointBinding" contract="IService" name="wsHttpEndpoint"> <!-- Upon deployment, the following identity element should be removed or replaced to reflect the identity under which the deployed service runs. If removed, WCF will infer an appropriate identity automatically. --> <!--identity> <dns value="https://mysslserver.com"/> </identity--> </endpoint> <!-- endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/ --> </service> </services> <behaviors> <endpointBehaviors> <behavior name="webBehavior"> <webHttp /> </behavior> </endpointBehaviors> <serviceBehaviors> <behavior name="ServiceBehavior"> <!-- Setup Security/Error Auditing --> <serviceSecurityAudit auditLogLocation="Application" suppressAuditFailure="false" serviceAuthorizationAuditLevel="Failure" messageAuthenticationAuditLevel="Failure" /> <serviceMetadata httpGetEnabled="false" httpsGetEnabled="true" httpsGetUrl="https://mysslserver.com/Service.svc"/> <serviceDebug includeExceptionDetailInFaults="false" /> <serviceCredentials> <!-- Use our own custom validation --> <userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="CustomValidator.CustomUserNameValidator, CustomValidator"/> </serviceCredentials> </behavior> </serviceBehaviors> <!-- serviceBehaviors> <behavior name="ServiceBehavior"> <serviceMetadata httpsGetEnabled="true" httpsGetUrl="https://mysslserver.com/Service.svc" /> To receive exception details in faults for debugging purposes, set the value below to true. Set to false before deployment to avoid disclosing exception information <serviceDebug includeExceptionDetailInFaults="true"/> </behavior--> </behaviors> </system.serviceModel> 
+4
source share
4 answers

I decided to give it one more hit, and I didn’t like having my custom validator in another library.

So, I created a new class in App_Code and went for it ...

The following is what is actually fixed,

 ="CustomValidator.CustomUserNameValidator, App_Code" 
+13
source

When you reference a custom validator with values

 ="CustomValidator.CustomUserNameValidator, CustomValidator" 

The first value is the type name, and the second is the assembly name in which the type can be found. Therefore, I would suggest that in your first case, your service is actually in some other assembly, such as MyService. In this case, you really need your configuration file to say

 ="CustomValidator.CustomUserNameValidator, MyService" 

I suspect that when you created a new class library for your validator, you named your project CustomValidator (which will output an assembly called CustomValidator.dll), and therefore config will now work (i.e. it has nothing to do with to being a separate class library - it just happens that the naming of your assembly link in web.config is now valid)

+9
source

It seems a little strange, but the solution was to create a separate class library and link to its DLL in my WCF service.

 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.IdentityModel.Selectors; using System.IdentityModel.Tokens; using System.ServiceModel; /// <summary> /// Summary description for CustomUsernamePasswordValidator /// </summary> namespace CustomValidator { public class CustomUserNameValidator : UserNamePasswordValidator { public override void Validate(string userName, string password) { if (null == userName || null == password) { throw new ArgumentNullException(); } if (!AuthenticateUser(userName, password)) throw new SecurityTokenValidationException("Invalid Credentials"); else { // do nothing - they're good } } public bool AuthenticateUser(string userName, string password) { if (userName != "userbill" || password != "passwordbill") { return false; } else { return true; } } } } 

Then I added a link to System.IdentityModel and System.ServiceModel.

The serviceCredentials section for WCF service now changes to this:

 <serviceCredentials> <!-- Use our own custom validation --> <userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="CustomValidator.CustomUserNameValidator, CustomValidator"/> </serviceCredentials> 

Hope this helps someone.

I tried this with invalid credentials and was expecting to see my "Invalid credentials" message. Instead, I get "At least one security token in the message could not be verified."

Also, this thing finally works and works!

+2
source

Just reading this, as it was useful for POC, I had to go fast. In response to ELHaix above ... this should work so that your descriptive user error is returned to the client:

 using System.ServiceModel ... throw new FaultException("Invalid Credentials - Custom Error"); 
0
source

All Articles