Here's what I've done so far:
1) Created an ASP.NET MVC relying party application and secured it with ADFS v2.0. This works.
2) Created a WCF Service using the Claims-Aware service template for an ASP.NET website. I've turned ASP.NET compatibility for the service ON because the service wouldn't activate otherwise. I've moved the interface for said service to a 'SharedContracts' assembly.
3) Set up the WCF service as a relying party using the "Add STS" reference, also pointing at my ADFS server.
4) Configured the ADFS server to include the WCF service as a relying party and issue it LDAP claims.
What I want to do now is talk to the service using ActAs. In other words, when someone hits HomeController.Index() from the ASP.NET MVC site with a token full of claims (remember the MVC site is a relying party), I want this method to programmatically create a client proxy and invoke the single service method I have on the WCF service (a method called "HelloClaim", which is nearly identical to the stock method that comes with the claims-aware service template).
Here's the code I've got so far:
[ValidateInput(false)]
public ActionResult Index()
{
SecurityToken callerToken = null;
IClaimsPrincipal claimsPrincipal = Thread.CurrentPrincipal as IClaimsPrincipal;
if (claimsPrincipal != null)
{
foreach (IClaimsIdentity claimsIdentity in claimsPrincipal.Identities)
{
if (claimsIdentity.BootstrapToken is SamlSecurityToken)
{
callerToken = claimsIdentity.BootstrapToken;
break;
}
}
string baseAddress = "http://khoffman2/SecureServices/Service.svc";
ChannelFactory<IHelloClaim> factory = new ChannelFactory<IHelloClaim>(new WebHttpBinding(), new EndpointAddress(baseAddress));
factory.ConfigureChannelFactory<IHelloClaim>();
IHelloClaim hello = factory.CreateChannelActingAs<IHelloClaim>(callerToken);
string result = hello.HelloClaim();
ViewData["Message"] = "Welcome to ASP.NET MVC!";
}
return View();
}
When I attempt to invoke the method, I get the following error message:
Manual addressing is enabled on this factory, so all messages sent must be pre-addressed.
I'm pretty sure I'm just not doing enough to configure the binding and the endpoint programmatically. If any of you have done this before or you know how to do it, I would love to be able to get this working.
Bottom line is I'm just making use of the basic identity delegation scenario - the only difference is I'm not using generated client proxies.
Take a look at this guide over at TechNet as it has a walkthrough on how to setup the scenario you've described:
http://technet.microsoft.com/en-us/library/adfs2-identity-delegation-step-by-step-guide(WS.10).aspx
In their example, I believe they are using standard WebForms, but in the case of MVC you can put the ChannelFactory initialization within the Global.asax within the Application_Start.
Related
I have an issue related with WCF Service and Web API with below steps.
Create a WCF Service Application which is Service1.svc
Right Click this project, and Add -> Web API -> Web API Controller Class
Could I host Web API in WCF solution like this? I did not find any place to configure or register Web API, so if I run this project, Web API will not run correctly.
Code For hosting web api
public class Service1 : IService1
{
public Service1()
{
var config = new HttpSelfHostConfiguration("http://localhost:8080");
config.Routes.MapHttpRoute(
"API Default", "api/{controller}/{id}",
new { id = RouteParameter.Optional });
using (HttpSelfHostServer server = new HttpSelfHostServer(config))
{
server.OpenAsync().Wait();
Console.WriteLine("Press Enter to quit.");
Console.ReadLine();
}
}
No, you can't add a web API controller into a WCF service project and expect it to work. WCF and WebAPI have almost no overlap in terms of their dependency on the BCL.
I think Prashant, in his comment, puts it very eloquently when he argues:
why you want to do this ?
You can host both a WebAPI project and a WCF service project in the same solution, but even though you can do this, why would you want to?
If you want to expose the same endpoints over both SOAP and REST you can already do this using only WCF.
I have a WPF client that is using WCF to call into a service hosted in IIS. My WCF client has AllowCookies='true' so that the forms authentication cookie that IIS is using is passed back and forth with each WCF call automatically. This all works just fine.
But I need the ability to clear out any forms authentication cookie my WCF client is caching so that my next request is not authenticated. Is there any way to do this?
On wcf client, you would have access to
HttpContext.Current.Request
Now this Request object contains cookies. You could loop over the cookie collection and remove the one you need.
foreach(var cookie in request.Cookies) { // }
An excellent article at code project which explains cookie management on WCF client
UPDATE
HttpContext is only available at server side, so my previous answer was incorrect as pointed by Phil.
The correct way to do it would be rather clumsy as you have get hold of HttpRequest itself
MyWebServiceClient client = new MyWebServiceClient();
using ( new OperationContextScope( client.InnerChannel ) )
{
HttpRequestMessageProperty request = new HttpRequestMessageProperty();
//get the instance of your AuthCookie and make it blank
request.Headers["AuthCookie"] = "";
OperationContext.Current.OutgoingMessageProperties[
HttpRequestMessageProperty.Name] = request;
client.InvokeSomeMethod();
}
Found this example here
I have such structure on my client.
WindowsIdentity wi = WindowsIdentity.GetCurrent();
IntPtr token = wi.Token;
Next step is send authentication token to server through WCF and impersonate user there.
api.SendToken(token);
...
...
...
But as soon I receive token on server side and trying to build WindowsIdentity it throws me an error:
WindowsIdentity newId = new WindowsIdentity(token);
Invalid token for impersonation - it cannot be duplicated.
Could you guys please help me to figure out what I am doing wrong and share your ideas how do I pass token from client to server.
Thanks!
WCF already has built-in plumbing to support Windows impersonation. Is there is a reason you're trying to roll your own?
UPDATE to avoid link-only answers (ahhh, errors of my youth...)
Here are the basic steps needed to configure the built in WCF impersonation
Only some bindings support Windows authentication. The WSHttpBinding is the most common one to support it but others may support it too.
On the service contract, use the OperationBehavior attribute on the method that requires impersonation:
[OperationBehavior(Impersonation=ImpersonationOption.Required)]
public string SomeMethod(string aParameter) { ... }
For the client, it is simplest to create a custom class inheriting from the ClientBase class. All service reference types inherit from this class. Here is an example of the client code:
var client = new SomeClientBaseDerivedType("TheServiceEndpoint");
client.ClientCredentials.Windows.AllowedImpersonationLevel =
System.Security.Principal.TokenImpersonationLevel.Impersonation;
I have developed one WCF application, and it is working as a middle layer between the database and my web application. Now my client wants to transfer this WCF to REST-based using ServiceStack.
I have looked around it on GitHub and tried to build a demo. I have created a start up template using NuGet, so it includes a Hello & Todo example.
How can I transfer my logic as object based (DTO)? Because most of the functions I have with different parameters and return the result as a dataset.
How can I make a client in C#? And which reference do I need to add?
When I hosted sample application on IIS after adding the startup template using NuGet, I could not able to find any resources. Is there a specific setting I need to do when I need to host it on IIS?
If you haven't already done so go through the Creating REST Services with ServiceStack presentation.
1) If you've seen ServiceStack's Hello World example it shows you that the only steps needed to do to create a web service is to just provide:
//1. A Request DTO
public class Hello : IReturn<HelloResponse> {
public string Name { get; set; }
}
//2. A Response DTO
public class HelloResponse {
public string Result { get; set; }
}
//3. The web service implementation that takes a Request DTO and returns a Response DTO
public class HelloService : Service
{
public object Any(Hello request)
{
return new HelloResponse { Result = "Hello, " + request.Name };
}
}
The above example shows all the code needed to create the Hello web service.
You should be able to re-use a lot of your existing type and logic from your WCF method and just copy it in the Any() method.
2) One of the benefits of ServiceStack is that you don't need to add a ServiceReference, i.e. you can re-use the same generic Service Client and your DTOs for all your web services. e.g:
//Using JSON:
IServiceClient client = new JsonServiceClient("http://localhost/path/to/servicestack");
//Using XML:
IServiceClient client = new XmlServiceClient("http://localhost/path/to/servicestack");
var response = client.Send(new Hello { Name = "Arun" });
Console.WriteLine("Received: " + response.Result);
On the /metadata page there is also a link to your webservices WSDL where you could create generated service clients should you wish. However this is not the recommended approach since it requires much more friction then just using your existing DTOs.
3) ServiceStack Web Services are already an ASP.NET application, i.e. ServiceStack is just a set of IHttpHandler's you can configure to run inside of a normal ASP.NET or MVC web application by adding a Web.config mapping to your web applications Web.config.
Basically you can treat a ServiceStack web service as a normal ASP.NET web application, in fact the Hello World Tutorial shows you how to do this from creating an empty ASP.NET application.
You may also be interested in checking out The Starter Templates example projects which shows you the minimum about of setup required to configure ServiceStack to run in a variety of different hosting options, i.e. ASP.NET / Windows Service / Console Application, etc.
I recently wrote a webservice to be used with Silverlight which uses the ASP.net membership and roles.
To validate the client in the service I look at the HTTPContext.Current.User (Which works when the service is called from Silverlight)
However, I've been trying to call the same service from an asp.net postback. But when I step-thru to the service the HTTPContext.Current has an emplty string for the username.
I'm guessing there is something that I'm not doing in the web.config file which is causing the httpContext to not be sent through the proxy to my service?
Any ideas would be appreciated. I need to be able to validate the client somehow using asp.net membership and roles and have it work from both an asp.net client and a silverlight client.
I have solved it!
Looks like by default the Silverlight application was sending all the browsers cookies to the service. One of these cookies is the ".ASPXAUTH" cookie to authenticate against the membership and roles.
The asp.net application however was not sending the cookies to the service. To send the authorisation cookie I used the following code before calling my webservice method.
using (OperationContextScope scope = new OperationContextScope(ws.InnerChannel))
{
HttpRequestMessageProperty httpRequest = new HttpRequestMessageProperty();
OperationContext.Current.OutgoingMessageProperties.Add(HttpRequestMessageProperty.Name, httpRequest);
HttpCookieCollection cc = Page.Request.Cookies;
if (Request.Cookies[".ASPXAUTH"] != null)
{
HttpCookie aCookie = Request.Cookies[".ASPXAUTH"];
String authcookieValue = Server.HtmlEncode(aCookie.Value);
httpRequest.Headers.Add("Cookie: " + ".ASPXAUTH=" + authcookieValue);
}
// Webservice call goes here
}
Instead of HTTPContext try ServiceSecurityContext.Current.PrimaryIdentity
Not sure how it is working from Silverlight but not ASP.Net, but for starters here is a good blog post on how to setup WCF to work with ASP.Net membership providers. There are quite a few steps so this could be pretty easy to miss a setting.
Once you get that working correctly then I imagine both should work correctly.
I think it may be because my wcf service is in my silverlight.web project, and perhaps they are more friendly when it comes to sharing.
I may need to read up more on wcf and create a greater seperation of concerns by setting up a seperate webservice project?
Update:
Ok I've taken a look at the HTTP Post request using Fiddler
Looks like the Silverlight App is sending a 'State' with an authorization cookie and my asp.net app isn't.
Looks like I need to send the state + my authorization cookie when I call the service. I may need to formulate a new question soon...