WCF and Custom Soap Authentication - wcf

I am developing a server application using WCF to expose WebService endpoints for clients. I want to implement authentication through a simple custom provider that will use the username and password passed through the SOAP headers. I know how to set the user name and password to be sent on the client, I just want to know how to pull the username and password out of the SOAP header on the server side. Any help would be greatly appreciated.

You need to specify the username and password validator in the service behavior
<behavior name="MyServiceBehavior">
<serviceCredentials>
<userNameAuthentication userNamePasswordValidationMode="Custom"
customUserNamePasswordValidatorType="MyNamespace.MyUserNamePasswordValidator, MyDll" />
</serviceCredentials>
</behavior>
you can access the user name and password from MyUserNamePasswordValidator class
public class MyUserNamePasswordValidator : UserNamePasswordValidator
{
public override void Validate( string userName, string password )
{
// valid your password here
}
}

Related

WCF - How to invoke Message Inspector before Service Authorization Manager?

We are using Message Inspector to customize the SOAP message by adding some information at client side and retrieving the added information at the server side.
We are also using Custom Authorization Manager by using ServiceAuthorizationManager to use retrieved SOAP based Message information.
To customize the SOAP messages, we are overriding two methods:
a) BeforeSendRequest (Client Side) - This method is used to customize the SOAP message header in Message Inspector.
public object BeforeSendRequest(ref System.ServiceModel.Channels.Message request, System.ServiceModel.IClientChannel channel)
{
Dictionary<string,string> headerInfo = new Dictionary<string,string>();
headerInfo.Add("UserId","1111");
MessageHeader header = MessageHeader.CreateHeader("LocalName", "NamespaceURI", headerInfo);
request.Headers.Add(header);
return null;
}
b) AfterReceiveRequest (Server Side) - This method is used to fetch the customized SOAP message in Message Inspector.
public object AfterReceiveRequest(ref System.ServiceModel.Channels.Message request, System.ServiceModel.IClientChannel channel, System.ServiceModel.InstanceContext instanceContext)
{
Dictionary<string, string> headerInfo = request.Headers.GetHeader<Dictionary<string, string>>("LocalName", "NamespaceURI");
return null;
}
Now, when request is made from the client side then first call is being made in Custom Authorization Manager class instead of AfterReceiveRequest() in Message Inspector at Server side.
We have registered our Custom Authorization Manager in the App.config file as shown:
<serviceBehaviors>
<behavior name="SampleAuthorizationService.Service1Behavior">
<serviceMetadata httpGetEnabled="false"/>
<serviceDebug includeExceptionDetailInFaults="false"/>
<serviceAuthorization principalPermissionMode="Custom" serviceAuthorizationManagerType="SampleAuthorizationSecurity.CustomAuthorizationManager, SampleAuthorizationSecurity">
<authorizationPolicies>
<add policyType="SampleAuthorizationSecurity.CustomAuthPolicy, SampleAuthorizationSecurity"/>
</authorizationPolicies>
</serviceAuthorization>
</behavior>
</serviceBehaviors>
The flow should be from Message Inspector to Custom Authorization Manager at server side. But, in our case the flow is exactly opposite i.e. from Custom Authorization Manager to Message Inspector.
This might be happening due to Registration of Custom Authorization Manager in the App.config.
Can anyone help me out to change the flow from Message Inspector to Custom Authorization Manager at server side?
I couldn't find a way to invoke Message Inspector before Service Authorization Manager, so I solved this problem by redefining method CheckAccess(OperationContext operationContext, ref Message message) in Service Authorization Manager and doing all the work in this method. It's not a pretty solution but it does the work :)

AuthorizeAttribute in WCF as MVC's

I'm new to WCF (Most of my time, I worked with ASP.NET Web API & MVC).
I wonder there is any AuthorizeAttribute in WCF or not (custom implementation is ok) .
For example:
+) In Web API, I have these steps :
-) Call [POST] api/login with email & password to login
-) Store email & password in front-end site, each time front-end sends a request, they have to include email & password in header for authentication.
-) In back-end, AuthorizeAttribute reads email & password of request header, do validation then authenticate the request as it is valid.
My question is:
Can my WCF application have an Attribute to do the same work as the API does ?
Thank you
You could implement your custom UserNamePasswordValidator:
public class MyValidator : UserNamePasswordValidator
{
public override void Validate(string user, string password)
{
// Do your validation logic.
// In case of unauthorized access throw appropriate exception.
}
}
And configure service behavior to use it:
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="behavior_name">
<serviceCredentials>
<userNameAuthentication userNamePasswordValidationMode="Custom"
customUserNamePasswordValidatorType="SomeNamespace.MyValidator, AssemblyName" />
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
Also it is not a good idea to store password. Would be better to generate an auth token by this login & password, and use that token.

RESTful WCF service security

How we could authenticate/authorize WCF RESTful service (that uses webHttpBinding (and not wsHttpBinding, like in SOAP case))?
I.e. we want to use Membership/Roles to permit (or prohibit) user consume each web method according his role.
Thanks in advance.
Ilan.
You can use certificates to secure the service or send the username and password in the header. You can then add a behavior by implementing IAuthorizationPolicy to the service so that you don't have to implement the security check in every web service method that you expose.
public class CertificateAuthorizationPolicy : IAuthorizationPolicy
{
public bool Evaluate(EvaluationContext evaluationContext, ref object state)
{
IIdentity identity;
object untypedIdentities;
if (!evaluationContext.Properties.TryGetValue("Identities", out untypedIdentities))
{
identity = null;
return false;
}
var identities = (IEnumerable<IIdentity>)untypedIdentities;
identity = identities.Where(item => item.AuthenticationType == "X509").FirstOrDefault();
var claimSet = (X509CertificateClaimSet)evaluationContext.ClaimSets[0];
var certificate = claimSet.X509Certificate;
}
In web.config you tell the service to use the authorization policy
<behavior name="CertificateSecurityServiceBehavior">
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="false" />
<serviceDebug includeExceptionDetailInFaults="true" />
<serviceAuthorization principalPermissionMode="Custom">
<authorizationPolicies>
<add policyType="CertificateAuthorizationPolicy, MyAssembly.Security" />
</authorizationPolicies>
</serviceAuthorization>
<dataContractSerializer maxItemsInObjectGraph="2147483647" />
</behavior>
Another option is to setup SSL on the IIS Server so that it requires SSL and client certificate to connect to any page.

Pass login information with each WCF Webservice call?

Hi,
I have set a WCF up as a webservice(percall), this webservice will getting request from a wide range of systems. Now we need somekind of way to identify the client.
Its possible to build a CustomUserNamePasswordValidation but this demands a secured(SLL) communication. In our case we do not need the security and the solution needs to be as easy as possible to setup.
So the question is how to send client identifikation(username/password) on each call?
I could place the identifikation data in the header but Im not sure how this can be tested with example soupUI? And Im not sure if all systems that will be communicate can handle this without complications?
Any sugestions?
Please note: I do only want to do 1 call, so no login service method should have to be used.
WCF do not suport sending user credentials unsecured. To solve this you could use the clear username binding or adding the credentials manually in the heador of the message(this is simple with WCF)
Define a binding in the web.config like :
<basicHttpBinding>
<binding name="BasicAuthBinding">
<security mode="Message">
<message clientCredentialType="UserName"/>
</security>
</binding>
</basicHttpBinding>
Then define a service behaviour like :
<behavior name="Namespace.TestBehaviour">
<serviceCredentials>
<userNameAuthentication userNamePasswordValidationMode="Custom"
customUserNamePasswordValidatorType="Namespace.ServiceSecurity.UserAuthenticator, Namespace" />
</serviceCredentials>
<serviceAuthorization>
<authorizationPolicies>
<add policyType="Namespace.ServiceSecurity.MyAuthorizationPolicy, Namespace" />
</authorizationPolicies>
</serviceAuthorization>
</behavior>
Then provide the custom authentication and authorization classes as follows :
public class MyAuthorizationPolicy: IAuthorizationPolicy
{
public bool Evaluate(EvaluationContext evaluationContext, ref object state)
{
IList<IIdentity> identities = (IList<IIdentity>) evaluationContext.Properties["Identities"];
foreach (IIdentity identity in identities)
{
if (identity.IsAuthenticated &&
identity.AuthenticationType == "UserAuthenticator")
{
evaluationContext.Properties["Principal"] = identity.Name;
return true;
}
}
if (!evaluationContext.Properties.ContainsKey("Principal"))
{
evaluationContext.Properties["Principal"] = "";
}
return false;
}
public ClaimSet Issuer
{
get { throw new NotImplementedException(); }
}
}
authentication as follows :
public class UserAuthenticator : UserNamePasswordValidator
{
public override void Validate(string userName, string password)
{
//authenticate me however you want
//then set whatever you want
}
}
If you need further security, change basicHttpBinding to a wsHttpBinding and use a certificate
EDIT : Almost forgot, use the defined service behaviour and binding in your service interface definition in web.config.
In the code :
public class WCF_Project_Authentification : UserNamePasswordValidator
{
#region UserNamePasswordValidator Interface Member
public override void Validate(string userName, string password)
{
if (userName != "Jeanc" || password != "fortin")
{
throw new FaultException("Authentification failed");
}
}
#endregion
}
In the config :
<behaviors>
<serviceBehaviors>
<behavior name="Service_Behavior">
<serviceMetadata httpGetEnabled="False" httpsGetEnabled="True"/>
<serviceDebug includeExceptionDetailInFaults="True"/>
<serviceCredentials>
<userNameAuthentication userNamePasswordValidationMode="Custom"
customUserNamePasswordValidatorType="WcfService.Authentification.WCF_Project_Authentification, WcfService"/>
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
And in the client code :
proxy.ClientCredentials.UserName.UserName = "Jeanc";
proxy.ClientCredentials.UserName.Password = "fortin";

Custom ASP.NET Forms Authentication Service with WCF

I am trying to create a custom ASP.NET Forms Authentication Service using WCF. I am calling it via a test page that contains only a single line of JS (except for the ScriptManager scripts). The problem is that the server returns response code 500 and the response body is empty. My breakpoints in the service method and in the Application_Error in Global.asax are not being hit.
Sys.Services.AuthenticationService.login('user', 'pass', false, null, null, null, null, null);
I can see the request go to the server in the browser tools with the following request body:
{"userName":"user","password":"pass","createPersistentCookie":false}
Other things on the request side also seem fine.
Here is the configuration service:
<system.serviceModel>
<behaviors>
<endpointBehaviors>
<behavior name="BtxAuthenticationEndpointBehavior">
<webHttp/>
</behavior>
</endpointBehaviors>
<serviceBehaviors>
</serviceBehaviors>
</behaviors>
<services>
<service name="MyNamespace.BtxAuthenticationService">
<endpoint contract="MyNamespace.IBtxAuthenticationService" binding="webHttpBinding" behaviorConfiguration="BtxAuthenticationEndpointBehavior"/>
</service>
</services>
</system.serviceModel>
And the declaration of the interface:
[ServiceContract]
public interface IBtxAuthenticationService
{
[OperationContract]
[WebInvoke]
bool Login(string username, string password, bool createPersistentCookie);
[OperationContract]
[WebInvoke]
void Logout();
}
The implementation:
public class BtxAuthenticationService : IBtxAuthenticationService
{
public bool Login(string username, string password, bool createPersistentCookie)
{
... irrelevant because this is never hit
}
public void Logout()
{
}
}
Can someone tell me how to configure this or point me to a way to debug it. An article about implementing custom Forms Authentication with a WCF service will be welcome too. I've tried experimenting with various other settings including all the exception details settings I could find but could not make any progress (though I was able to make some regress and get different exceptions like missing endpoints and so on).
Thank you for your time.
Not sure if this helps. I have never written such service but your configuration creates WCF service wich is not ASP.NET AJAX ready and works with XML instead of JSON. Try to use this instead of webHttp behavior:
<endpointBehaviors>
<behavior name="BtxAuthenticationEndpointBehavior">
<enableWebScript />
</behavior>
</endpointBehaviors>