Writing a Secure WCF Data Service for Excel PowerPivot [closed]
-
10-10-2019 - |
Pergunta
I'm having some trouble writing a secure WCF data service to be consumed by PowerPivot. The service works fine, and I can consume the data in PowerPivot without trouble.
My issue is that when I enter the user ID and password for the Data Feed in PowerPivot (in Data Feed advanced settings), I can't seem to get any access to them from inside the WCF service. I'd like to use both the user ID and password to authenticate against a database, but I need to get at them first. :)
Are there any good examples of how to write a secure WCF Data Service specifically for PowerPivot?
Thanks very much.
Solução
I was struggling with this same thing, and after some research found this blog post that got me rolling:
http://pfelix.wordpress.com/2011/04/21/wcf-web-api-self-hosting-https-and-http-basic-authentication/
In short, there is some work you need to do to allow the Principal to flow through to the service call.
Outras dicas
There's a full downloadable sample on MSDN
WCF Data Service with basic authentication for PowerPivot clients
https://code.msdn.microsoft.com/office/WCF-Data-Service-with-547e9341
Update
Okay, now I've used the code in the link (that I was researching at the time I posted) I know that it works, so here's the code example:
Step 1: Write an HTTP handler to handle all requests and perform the authentication (or issuance of a 401 challenge).
namespace WebHostBasicAuth.Modules
{
public class BasicAuthHttpModule : IHttpModule
{
private const string Realm = "My Realm";
public void Init(HttpApplication context)
{
// Register event handlers
context.AuthenticateRequest += OnApplicationAuthenticateRequest;
context.EndRequest += OnApplicationEndRequest;
}
private static void SetPrincipal(IPrincipal principal)
{
Thread.CurrentPrincipal = principal;
if (HttpContext.Current != null)
{
HttpContext.Current.User = principal;
}
}
// TODO: Here is where you would validate the username and password.
private static bool CheckPassword(string username, string password)
{
return username == "user" && password == "password";
}
private static void AuthenticateUser(string credentials)
{
try
{
var encoding = Encoding.GetEncoding("iso-8859-1");
credentials = encoding.GetString(Convert.FromBase64String(credentials));
int separator = credentials.IndexOf(':');
string name = credentials.Substring(0, separator);
string password = credentials.Substring(separator + 1);
if (CheckPassword(name, password))
{
var identity = new GenericIdentity(name);
SetPrincipal(new GenericPrincipal(identity, null));
}
else
{
// Invalid username or password.
HttpContext.Current.Response.StatusCode = 401;
}
}
catch (FormatException)
{
// Credentials were not formatted correctly.
HttpContext.Current.Response.StatusCode = 401;
}
}
private static void OnApplicationAuthenticateRequest(object sender, EventArgs e)
{
var request = HttpContext.Current.Request;
var authHeader = request.Headers["Authorization"];
if (authHeader != null)
{
var authHeaderVal = AuthenticationHeaderValue.Parse(authHeader);
// RFC 2617 sec 1.2, "scheme" name is case-insensitive
if (authHeaderVal.Scheme.Equals("basic",
StringComparison.OrdinalIgnoreCase) &&
authHeaderVal.Parameter != null)
{
AuthenticateUser(authHeaderVal.Parameter);
}
}
}
// If the request was unauthorized, add the WWW-Authenticate header
// to the response.
private static void OnApplicationEndRequest(object sender, EventArgs e)
{
var response = HttpContext.Current.Response;
if (response.StatusCode == 401)
{
response.Headers.Add("WWW-Authenticate",
string.Format("Basic realm=\"{0}\"", Realm));
}
}
public void Dispose()
{
}
}
}
Step 2: Configure your new handler with IIS via your web.config.
<system.webServer>
<modules>
<add name="BasicAuthHttpModule"
type="WebHostBasicAuth.Modules.BasicAuthHttpModule, YourAssemblyName"/>
</modules>
...
Important for Excel PowerPivot
See this bug: PowerPivot not sending Authorization header in Basic Authentication to OData Svc