Restricting Web Service Calls in Azure - asp.net

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.

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

Asp.net delegation

I am making a .Net Web API that gets data by calling an SQL server. The user is authenticated via Windows Authentication (Kerberos). I would like the user credentials to be passed to the SQL server via delegation, but the SQL server sees an anonymous user.
This is what I have done:
IIS application:
Windows Authentication and asp.net impersonation enabled. Anonymous and forms authentication disabled.
Enable kernel mode authentication is checked.
Providers: Negotiate, Kerberos.
Use app pool credentials: True.
Application pool:
Managed pipeline mode: Classic.
Identity: Network service.
In AD, the computer the web server runs on is set to "Trust this computer for delegation to any specific service (Kerberos only)"
The connection string to the SQL server contains Integrated Security=SSPI;
Edit: In my web.config I have
<system.web>
<authentication mode="Windows" />
<identity impersonate="true" />
</system.web>
and
<security>
<authentication>
<windowsAuthentication enabled="true">
<providers>
<clear />
<add value="Negotiate" />
<add value="Kerberos" />
</providers>
<extendedProtection tokenChecking="None" />
</windowsAuthentication>
<anonymousAuthentication enabled="false" />
</authentication>
</security>
The generic HOST spn is set for the machine.
From the browser I access the web application via http://machinename.domain.net.
I would expect in this setup that my IIS application is run under the machine account?
When I catch a request in the debugger on the web server, I can see that WindowsIdentity.GetCurrent().Name is the account of the user browsing the web application and WindowsIdentity.GetCurrent().AuthenticationType is set to "Kerberos". So that should be good.
However WindowsIdentity.GetCurrent().ImpersonationLevel is only set to "Impersonate". I would have expected it to be set to "Delegate"?
When I make a request to the SQL server, I get "Login failed for user 'NT AUTHORITY\ANONYMOUS LOGON'" so obviously the user credentials are not passed to the SQL server.
I hope someone can see what I am doing wrong. I really need a push in the right direction.
For future reference if someone runs into the same issue:
The issue was that we tried from Chrome. It works in IE, but on Chrome the registry change mentioned in this post was needed: Kerberos delegation doesn't work in chrome
You should be able to set the Authentication to ASP.NET Impersonation within IIS. You will probably be required to set the following in your web.config file too, as part of < system.web> section.
<identity impersonate="true" />
This may be required in the < system.webServer> section to, although not always recommended due to security concerns.
<validation validateIntegratedModeConfiguration="false" />

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/

Basic authentication for the web service

I'm having problems to set up the basic authentication for the web service.
I'm writing standard web service (not WCF) using .NET 4.0
In the web.config I have the following settings:
<configuration>
<system.web>
<identity impresionate="true" />
<authentication mode="Windows" />
</system.web>
...
</configuration>
The web service has one method:
[WebMethod(Description = "Returns currently logged in user.")]
public string WhoAmI()
{
return "You are logged in as: " + System.Threading.Thread.CurrentPrincipal.Identity.Name;
}
The test server is virtual machine located on the same domain as my machine. When I access it, I don't get anything for the CurrentPrincipal.Identity.Name.
I also tried to access the web service using the soapUI. I entered my username, password and domain but I still can't get it to work.
Any help would be appreciated.
On IIS (inetmgr) you can find Authendication Method window.(WebService1->Properties->Directory Security->Authendication Controls->Edit Button)
You can choose Authendicated access. (Diggest,Basic,Integrated Authendication)
After that changing your method will work as you want.
Does it work if you change impresionate to impersonate?

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

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

Resources