WCF, ASP.NET Compatibility Mode and custom authentication using membership providers - asp.net

I need help in following:)
To begin with I work on the large application, that has a WinForms client and server. Server in our case is the set of WCF services. There is one service that is responsible for authentication of users. The logic of authentication is custom and complex and authentication service uses different membership providers.
We want to protect the access to server services for non-authenticated users. The users must firstly authenticate and than use other services (users in this case are the other systems, services, WinForms client, etc.). On this basis, we decided to use the ASP.NET Url/File Authorization feature.
So, I set on the ASP.NET compatibility mode, allowed cookie in all binding configurations, added AspNetCompatibilityRequirements attribute to our services and added the followingconfigurations to config:
<authentication mode="Forms">
<forms cookieless="UseCookies">
<credentials passwordFormat="Clear" />
</forms>
</authentication>
<authorization>
<deny users="?" />
</authorization>
...
<location path="AuthenticationService.svc">
<system.web>
<authorization>
<allow users="*" />
</authorization>
</system.web>
</location>
In the authenticate method of our authentication service I add the following code:
public AuthenticationResult AuthenticateUser(string username, string password)
{
AuthenticationResult result = new AuthenticationResult();
result = Authenticate(username, password);
if (result.IsAuthenticated)
FormsAuthentication.SetAuthCookie(username, true);
return result;
}
Next, I wrote the following code:
var authClient = new AuthenticationServiceClient();
var result = authClient.AuthenticateUser("user", "password");
var otherClient = new OtherServiceClient();
var temp = otherClient.DoSomething();
But after authentication I can't access to OtherServiceClient...
So, how can I share the call context between the WCF services calls? Could anybody provide some useful articles about this question?
Thanks in advance!
Best regards.

You need to:
1) Enable sessions in WCF
2) Authenticate using WCF
3) Keep reusing your proxies instead of creating new ones.
This is useful:
http://msdn.microsoft.com/en-us/library/ms733040.aspx

Related

Form Authentication vs OWIN UseCookieAuthentication and subdomain SSO

Is the "traditional" form authentication and owin middleware(with UseCookieAuthentication) are perfectly interchangeable?
I'd like to make a simple subdomain sso (like many examples suggest)
Sharing authentication between parent and child web applications
my parent application is an old asp.net webform application with form authentication configured in web.config
<system.web>
<authentication mode="Forms">
<forms loginUrl="~/Account/Login" timeout="2880" name=".ASPXAUTH" protection="Validation" domain="localhost" />
</authentication>
<machineKey validationKey="E0230924313583BE9D071B5826165A7C6198A1697AE2F549535F0744FFDC414638882DDC507C7B097EAD5B4FB67819D9520D0A9D05B2D38EAB4AF0B36DAAA39F" decryptionKey="D29E22658319B16CAE17C9CD0269AB15DEAF9068FB6D459C" validation="SHA1" decryption="AES"></machineKey>
</system.web>
and a child application (in a subdomain) that is an asp.net Mvc5 (with owin UseCookieAuthentication)so the security is configured in Startup.cs and not in the web.config
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
CookieName = ".ASPXAUTH",
CookieDomain "localhost"
Provider = new CookieAuthenticationProvider { OnApplyRedirect = ApplyRedirect }
});
private static void ApplyRedirect(CookieApplyRedirectContext context)
{
Uri absoluteUri;
if (Uri.TryCreate(context.RedirectUri, UriKind.Absolute, out absoluteUri))
{
var path = PathString.FromUriComponent(absoluteUri);
if (path == context.OwinContext.Request.PathBase + context.Options.LoginPath)
context.RedirectUri = "http://localhost/subSiteAuthenticationTest/Account/Login" +
new QueryString(
context.Options.ReturnUrlParameter,
context.Request.Uri.AbsoluteUri);
}
context.Response.Redirect(context.RedirectUri);
}
in the child application web.config i configured only the same machine key to the parent application
<system.web>
<authentication mode="None">
<machineKey validationKey="E0230924313583BE9D071B5826165A7C6198A1697AE2F549535F0744FFDC414638882DDC507C7B097EAD5B4FB67819D9520D0A9D05B2D38EAB4AF0B36DAAA39F" decryptionKey="D29E22658319B16CAE17C9CD0269AB15DEAF9068FB6D459C" validation="SHA1" decryption="AES"></machineKey>
</system.web>
the parent's login page is used for both application (in order to use an absolute path for the login page in the chil application i implemented "OnApplyRedirect" as this post says: Login page on different domain)
but this doesn't work, did i miss somthing?
Is the "traditional" form authentication and owin middleware(with UseCookieAuthentication) are perfectly interchangeable?
Unfortunately, no, they're not interchangable.
You can, however, provide a custom TicketDataFormat in the CookieAuthenticationOptions.
Here's an example.
SSO for ASP.NET MVC4 and MVC5 web apps shared the same domain

Restricting Web Service Calls in Azure

I have a web site that makes calls to a web service. The web service currently restricts calls to be made only from the web site using IP restriction.
Now I am trying to move both sites to Azure Websites but I can no longer depend on a static IP address for calls from the web site because Azure Websites do not support static IPs for out-bound calls.
Azure Websites also do not accept client certificates.
How to I restrict calls to my web service to only be from my web site?
Since Azure Web Sites do not accept client certificates, I decided to take another approach. This solution uses ASP.NET's Forms Authentication and authorize a system user between services.
For this to work, each server must enable Forms authentication and be assigned the same machine key. I found it only works with the compatibility mode set to Framework45.
<system.web>
<machineKey compatibilityMode="Framework45"
validation="SHA1"
validationKey="14E2DFC..."
decryption="AES"
decryptionKey="93923..."/>
<authentication mode="Forms">
<forms loginUrl="/SecurityService.asmx?op=authenticate" />
</authentication>
<authorization>
<deny users="?" />
<allow users="System" />
</authorization>
</system.web>
Then generate and add a Forms authentication cookie to your web service (or any other HTTP call). Note that the Forms cookie had to be converted to a System.Net.Cookie.
var websiteService = new WebsiteService.WebsiteService();
websiteService.CookieContainer = new System.Net.CookieContainer();
var websiteServiceUrl = new Uri(websiteService.Url);
var authCookie = FormsAuthentication.GetAuthCookie("System",
false,
FormsAuthentication.FormsCookiePath);
var authenticationCookie = new System.Net.Cookie(FormsAuthentication.FormsCookieName,
authCookie.Value,
FormsAuthentication.FormsCookiePath,
websiteServiceUrl.Host);
websiteService.CookieContainer.Add(authenticationCookie);
Now all your authorizations can be configured in the authorization element in your web.config file as shown above.

How can I add token authentication to my IIS so as to secure files in a folder?

I have a Windows Azure WebAPI application with
OWIN
Oauth 2
token authentication
Identity 2 Framework
VS2013 Update 2
IIS (I am not sure which version. As I just updated everything in the stack then I assume the latest version)
Before a user is authenticated when there's a <script> in my index.html file I notice cookies sent to the server looking like this:
Accept-Language: en-US,en;q=0.8
Cookie: .AspNet.Cookies=GWLL4LgeFkn7jDndAwf-Pk_eZAPZ5LYZugSmv- ...
After a user is authenticated I notice the cookies change:
Accept-Language: en-US,en;q=0.8
Cookie: .AspNet.Cookies=OqLMSpIv2aQ8KUcw3pWdAYtPYUI_tYMl4rEYKe16N ...
I thought I was using token authentication so my first question is "why do the cookies get changed and why are they sent at all"?
Once a user is authenticated then with each $http request to the server I send a header like this:
Authorization: Bearer abcdefgetc....
My authorization on the server works when I have WebAPI methods decorated like:
[Authorize(Roles = "Admin")]
Here is the main web-config that shows the security settings:
<system.web>
<authentication mode="None" />
<compilation debug="true" targetFramework="4.5.1" />
<httpRuntime targetFramework="4.5.1" />
</system.web>
<system.webServer>
<modules>
<remove name="FormsAuthenticationModule" />
</modules>
</system.webServer>
Now I would like to add some security to some static javascript files that I have on the server. I know how I can code it so the files can be retrieved by my client and added to the DOM in two ways. Either way is okay for me to use although I prefer the first way if when I do that way then there can be authentication happen through cookies or otherwise:
With a script tag and a load
var el = doc.createElement("script"),
loaded = false;
el.onload = el.onreadystatechange = function () {
if ((el.readyState && el.readyState !== "complete" && el.readyState !== "loaded") || loaded) {
return false;
}
el.onload = el.onreadystatechange = null;
loaded = true;
// done!
};
el.async = true;
el.src = path;
document.getElementsByTagName('head')[0].insertBefore(el, head.firstChild);
With a $http call and then adding it directly to the DOM (I can supply bearer token)
$http({
url: '/Bundles/admin/admin1Bundle.js',
method: "GET"
})
.success(function (result) {
var m = document.createElement('script');
m.appendChild(document.createTextNode(result));
document.getElementsByTagName('head')[0].appendChild(m);
Once added the javascript becomes available. To add security I created a web.config in the folder to protect these files and allow only users with Admin role to have access:
Here is the folders web-config that shows the security settings:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.webServer>
<security>
<authorization>
<remove users="*" roles="" verbs="" />
<add accessType="Allow" roles="Admin" verbs='GET'/>
</authorization>
</security>
</system.webServer>
</configuration>
When a user with the role of Admin tries to access files in the folder with a GET that a has a bearer token they get a message saying:
Most likely causes:
•No authentication protocol (including anonymous) is selected in IIS.
•Only integrated authentication is enabled, and a client browser was used that does not support integrated authentication.
•Integrated authentication is enabled and the request was sent through a proxy that changed the authentication headers before they reach the Web server.
•The Web server is not configured for anonymous access and a required authorization header was not received.
•The "configuration/system.webServer/authorization" configuration section may be explicitly denying the user access.
This error occurs when the WWW-Authenticate header sent to the Web server is not supported by the
server configuration. Check the authentication method for the resource, and verify which authentication
method the client used. The error occurs when the authentication methods are different. To determine
which type of authentication the client is using, check the authentication settings for the client.
It seems like my IIS (the version I am using on my development environment when I click Debug > Start Debugging) is using a different kind of authentication from that used by my WebAPI. Can someone explain to me:
Should I be using <system.web> or <system.webServer> for the security?
How can I make the IIS use the same security path as WebAPI is using when I decorate my WebAPI methods? Note that I need a way to do this with web.config as I don't have access to make changes to the IIS directly once the application is published to the cloud.
I am using token authentication so why is the cookie information sent? Could I just use this cookie information to secure my javascript files from getting downloaded?
Notes:
Here is the way I have authentication set up in Startup.Auth.cs
// Configure the application for OAuth based flow
PublicClientId = "self";
OAuthOptions = new OAuthAuthorizationServerOptions
{
TokenEndpointPath = new PathString("/Token"),
Provider = new ApplicationOAuthProvider(PublicClientId),
AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
AllowInsecureHttp = true
};
// Enable the application to use bearer tokens to authenticate users
app.UseOAuthBearerTokens(OAuthOptions);
Should I be using or for the security?
How can I make the IIS use the same security path as WebAPI is using
when I decorate my WebAPI methods? Note that I need a way to do this
with web.config as I don't have access to make changes to the IIS
directly once the application is published to the cloud.
You could use the authorization attribute in the webconfig to restrict files and folders, the example below restricts restricts a specific js file to admins only.
<location path="resources/scripts/yourtopsecretjsfile.js">
<system.webServer>
<security>
<authorization>
<remove users="*" roles="" verbs="" />
<add accessType="Allow" roles="Administrators" />
</authorization>
</security>
</system.webServer>
</location>
I am using token authentication so why is the cookie information sent?
It is used by the server to identify the authenticated user. If you don't want to do without sending the cookie info you can look at doing at sending a signed token with every request instead. Check out this article, loosely covers how to do that (but that with an angular JS/ Web API 2 point of view) http://bitoftech.net/2014/06/01/token-based-authentication-asp-net-web-api-2-owin-asp-net-identity/

Role-based Security without Forms Authentication in ASP .NET

I would like to take advantage of:
Page.User.IsInRole("CustomRole");
Page.User.Identity.IsAuthenticated
when working inside Page methods, as well as authorization section in web.config:
<authorization>
<allow roles="Administrators, Supervisors" />
<deny users="*" />
</authorization>
and also apply rules on classes and methods level:
[PrincipalPermission(SecurityAction.Demand, Role = "Administrators")]
In my application I authenticate with ... custom mechanism that provides me user identity in ... http header. I get users PIN number (some kind of ID) + roles. But that is a side plot. It doesn't matter.
What I actually want to achieve is to take advantage of ASP .NET build in Authorization features but having my custom authentication mechanism. I guess I have to implement IPrincipal and IIdentity, is that right? I saw plenty of samples on the web but all of them include web.config configuration that specifies providers, and also FormsAuthentication like classes, that I guess I don't need. I just need to inject my user object (which is prepared by me) into request and that's it.
So:
what's the easiest way to achieve it?
what is the difference between GenericPrincipal / IPrincipal?
how to get/create IIdentity object? I saw samples with:
var id = new FormsIdentity(authTicket);
but I'm not using FormsAuthentication.
Thanks
In short, you have to implement your own authentication module.
An authentication module is just an ASP.NET module but having special purpose. Its AuthenticateRequest method should populate HttpContext.Current.User property with an instance of IPrincipal.
Answering your other questions: IPrincipal is just an interface while GenericPrincipal is one of its implementations. You can use it, as the name suggests it's just a generic implementation which means that it should suit you. Since IPrincipal is just IIdentity plus roles, you probably will also need GenericIdentity.
Other implementations, like RolePrincipal + FormsIdentity are designed for specific purposes, these two for example are used by the Forms Authentication Module.
There are some good examples available, just google for "custom authentication module".
Before you do (create/implement your own), have you tried/considered adapting Forms Authentication to your existing auth scheme?
I think you're "almost there" (using all of the built-in ASP.net auth/membership/profiles/roles), and it maybe easier/simpler to just "plug in" your existing auth scheme into Forms Authentication.
This snippet of code should give you an idea of how flexible Forms Authentication can be:
if ((UserEmail.Text == "jchen#contoso.com") && (UserPass.Text == "37Yj*99Ps"))
{
FormsAuthentication.RedirectFromLoginPage
(UserEmail.Text, Persist.Checked);
}
else
{ ... }
So, it works with a hard coded "auth scheme" (not that you should, but gives you an idea of the possibilities), or even a list in web.config - again, just a sample:
<authentication mode="Forms">
<forms name=".FUBAR">
<credentials passwordFormat="MD5">
<user name="foo" password="b7ab5072e8fba7bed20384cc42e96193"/>
<user name="bar" password="1c42e49a360aa7cc337a268a1446a062"/>
<user name="john" password="5f4dcc3b5aa765d61d8327deb882cf99"/>
<user name="jane" password="7c6a180b36896a0a8c02787eeafb0e4c"/>
</credentials>
</forms>
</authentication>
Just a thought - hth....

login control forms authentication

I setup a login control to use on my web application and having issues validating the users. I created the membership tables in my own database in sql server 2008 using a suggestion on another site. Then I opted to just use forms authentication and created two users in the WSAT and thought that this would work fine. But it returns false for all users including the two I created. Why this is so I am not sure and if I were to use the sql database tables how would I do this?
<authentication mode="Forms">
</authentication>
<authorization>
<allow users="boy"/>
<allow users="girl"/>
</authorization>
<roleManager enabled="true" />
code behind login:
If Page.IsValid then
If username <>"" and password <>"" then
If FormsAuthentication.Authenticate(username,passwprd) = False then
Return false
else
response.redirect("~/default.aspx")
End If
End If
End If
You need to configure your web.config to use the MembershipProvider.
Take a look here for more info. Are you trying to use the SqlMembershipProvider?
To authenticate using MembershipProvider use the Login user control or you can create your own and call the following methods:
if (Membership.ValidateUser(username, password))
{
FormsAuthentication.SetAuthCookie(userName, createPersistentCookie);
FormsAuthentication.RedirectFromLoginPage(userName, createPersistentCookie);
}

Resources