I am trying to write an ASP.NET MVC application which is a frontend to our CRM which has a SOAP web service. I would like the user to log in to my web application using their CRM username and password, and then authenticate against CRM, make web service calls on the pages etc.
I started to look at using Forms Authentication and implementing a custom membership provider - I can implement all the methods I need to like ValidateUser()
, but the problem I have is that after logging in to the CRM web service you are given a token which has to be passed with every subsequent web service call, and I am not sure where I can store this.
So my questions are:
Any advice would be appreciated
You can store the authentication token in the userData part of the forms authentication cookie. This way it will be available on each request.
So for example once you verify the credentials of a user you could query the web service to obtain the token and manually create and emit the forms authentication cookie:
[HttpPost]
public ActionResult LogOn(string username, string password)
{
// TODO: verify username/password, obtain token, ...
// and if everything is OK generate the authentication cookie like this:
var authTicket = new FormsAuthenticationTicket(
2,
username,
DateTime.Now,
DateTime.Now.AddMinutes(FormsAuthentication.Timeout.TotalMinutes),
false,
"some token that will be used to access the web service and that you have fetched"
);
var authCookie = new HttpCookie(
FormsAuthentication.FormsCookieName,
FormsAuthentication.Encrypt(authTicket)
)
{
HttpOnly = true
};
Response.AppendCookie(authCookie);
// ... redirect
}
Then you could write a custom authorize attribute which will read this information and set a custom generic identity:
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited = true, AllowMultiple = true)]
public class MyAuthorizeAttribute : AuthorizeAttribute
{
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
var isAuthenticated = base.AuthorizeCore(httpContext);
if (isAuthenticated)
{
string cookieName = FormsAuthentication.FormsCookieName;
if (!httpContext.User.Identity.IsAuthenticated ||
httpContext.Request.Cookies == null ||
httpContext.Request.Cookies[cookieName] == null)
{
return false;
}
var authCookie = httpContext.Request.Cookies[cookieName];
var authTicket = FormsAuthentication.Decrypt(authCookie.Value);
// This is where you can read the userData part of the authentication
// cookie and fetch the token
string webServiceToken = authTicket.UserData;
IPrincipal userPrincipal = ... create some custom implementation
and store the web service token as property
// Inject the custom principal in the HttpContext
httpContext.User = userPrincipal;
}
return isAuthenticated;
}
}
Finally decorate your controllers/actions that require authentication with this attribute:
[MyAuthorize]
public ActionResult Foo()
{
// HttpContext.User will represent the custom principal you created
// and it will contain the web service token that you could use to
// query the remote service
...
}