Situation
I have a Silverlight application that uses a WCF backend. Going forward we have moved to JS clients with WebAPI.
I have a couple of WebAPI controllers that I would like to use from the Silverlight client and so have them loaded within the ASP.Net application that hosts the WCF services.
This works fine from a "all services are available" point of view, however Authorization is being invoked multiple times for WCF calls; from OWIN and through WCF ServiceAuthorizationManager
On the WCF side, my ServiceAuthorizationManager implementation validates the token in the AuthHeader and then transforms that token (in the System.IdentityModel Claims Transformation sense). On the WebAPI side I'm using Thinktecture.IdentityModel which provides OWIN Middleware to do token validation and claims transformation .
Problem is, the OWIN middleware gets invoked for all requests (including the WCF requests). So in the case of a WCF request I get validation and transformation executed twice. I can't just remove the ServiceAuthorizationManager and let the middleware handle it, because WCF knows nothing of OWIN and the final step of the ServiceAuthorizationManager is to set the operation context principal (different to ClaimsPrincipal.Current).
Question
Has anyone had a problem like this before with WCF and WebAPI sitting side by side? Would the best approach be to somehow drop out of the OWIN pipeline very early on for WCF calls and if so how can that be done, through an OMC? Or can I somehow use the IAppBuilder.Map approach to only register the token validation and transformation components for API routes (in this case anything starting /api)?
I've managed to get this to work via a Branched Pipeline.
app.MapWhen(c => c.Request.Path.Value.Contains("/api"),
subApp =>
{
subApp.UseJsonWebToken(
issuer: clientDetails.Issuer,
audience: clientDetails.Audience,
signingKey: clientDetails.SigningKey);
subApp.UseClaimsTransformation(transformer.Transform);
var webApiConfig = WebApiConfig.Configure();
webApiConfig.DependencyResolver = StructureMapConfig.HttpDependencyResolver();
subApp.UseWebApi(webApiConfig);
});
Only thing I'm wondering is why IAppBuilder.MapWhen as above works, but when I use IAppBuilder.Map it doesn't seem to work...
app.Map("/api",
subApp => ...
Big thanks to the answer above. With this piece of code, I was able to figure out how to conditionally route calls so that WCF calls are not grabbed by static content middleware.
//app.UseMiddleware<ServeStaticFilesMiddleware>();
app.MapWhen(c => !c.Request.Path.Value.Contains(".svc"),
subApp =>
{
subApp.UseMiddleware<ServeStaticFilesMiddleware>();
});
Related
I have managed to make default template work (my blazor standalone SPA should acquire tokens for several scopes from different ADApps - webAPIs; I've managed to get token only for one scope at the time even if I defined additionalScopes or defaultaccesstokenscopes).
builder.Services.AddMsalAuthentication(options =>
{
var config = options.ProviderOptions;
config.Authentication.Authority = "https://login.microsoftonline.com/tenantID";
config.Authentication.ClientId = "clientID";
options.ProviderOptions.DefaultAccessTokenScopes.Add("offline_access");
options.ProviderOptions.DefaultAccessTokenScopes.Add("https://graph.microsoft.com/user.read");
options.ProviderOptions.DefaultAccessTokenScopes.Add("https://tenant.crm.dynamics.com/user_impersonation");
options.ProviderOptions.DefaultAccessTokenScopes.Add("clientID/scope1");
// tried this too
// config.AdditionalScopesToConsent.Add("https://tenant.crm.dynamics.com/user_impersonation");
});
Now there is a question on how to get the other tokens because it gets the token only for 'clientID' scope if multiple scopes are mentioned...? and use those tokens from wasm page in HttpClient request?
In angular (with MSAL) this is all done automatically, you define scopes you want and it gets all the tokens. Then it intercepts all requests and adds authorization header and corresponding token by domain of the request.
Is there similar mechanism here or should this be done manually by adding corresponding token for every request and using HttpRequestMessage with HttpClient.SendAsync()?
Obviously for business application there is not much of a use without contacting some kind of protected API, which is usually an app in the same AAD. For example let's say it can be a simple query to the Dynamics CRM's webapi.
I'm looking for some guidance on how to implement authorization security for SignalR on a back end service running in a self-hosted (non-IIS) environment, that is called from a Web application. The backend app is basically a monitor that fires SignalR events back to the HTML based client. This all works fine (amazingly well actually).
However, we need to restrict access to the server for authenticated users from the Web site. So basically if a user is authenticated on the Web site, we need to somehow pick up the crendentials (user name is enough) and validation state in the backend app to decide whether to allow the connection as to avoid unauthorized access.
Can anybody point at some strategies or patterns on how to accomplish this sort of auth forwarding?
I am having similar issues here, as in my web app I use a simple cookie authentication system which uses an AoP style approach to check for any controllers with an attribute, then will get the current context (be it from the static HttpContext.Current or from the target invocation object depending on the type of interceptor) and then verify the cookie exists, it contains right data, then finally verify the token with the db or cache etc.
Anyway this approach can also be used for Signalr, although its a bit more long winded and you are using dependency injection. You would basically wrap the hub calls with the desired attribute, then set up your DI/IoC configuration to intercept these calls, then either get the hub instance within your interceptor and get the cookie (or your custom authentication mechanism) from the request, verify it is all valid or not, and if not then throw a new HttpException("403", "Not authenticated"); which should kick the user out and return back before it even hits your hub method, this way you can put the logic in one place (your interceptor, or a class the interceptor consumes) then just wrap any method that needs to use this authentication using your attribute.
I use Ninject and the interception extension, but most major DI frameworks these days have some form of IoC plugin/extensions, such as Autofac, Windsor, Spring etc.
If you were not happy going down the route of introducing DI and/or AOP to your current project, then maybe you could just create a custom hub instance which contains your authentication logic and then just use that in your hubs, so ok you will still be manually calling some authentication logic from within each hub method you want to protect, but its less code, so something like:
public class AuthorisableHub : Hub
{
private ISomeAuthenticationToken GetSomeAuthenticationTokenFromRequest(Request request) // probably a SignalR specific request object
{
// Get your token from the querystring or cookie etc
}
private bool IsAuthenticationTokenValid(ISomeAuthenticationToken token)
{
// Perform some validation, be it simple or db based and return result
}
protected void PerformUserAuthentication()
{
var token = GetSomeAuthenticationTokenFromRequest(Context.Request);
var isRequestValid = IsAuthenticationTokenValid(token);
if(!isRequestValid)
{ throw new HttpException(403, "<Some forbidden message here>"); }
}
}
public class MyFancyPantsHub : AuthorisableHub
{
public void TellAllClientsSomethingSecret(ISecret secret)
{
PerformUserAuthentication();
// Do stuff with the secret as it should have bombed the user out
// before it reaches here if working correctly
}
}
It is not perfect but would work (I think), also I am sure I once read somewhere that Hubs are newly instantiated for each request, and if this is indeed true, you could possibly just put this logic in your constructor if you want to apply the authentication to every action within the hub.
Hope that helps, or gives you ideas... would be interested in knowing how you did solve it in the end.
SignalR does not provide any additional features for authentication. Instead, it is designed to work with the authentication mechanism of your application.
Hubs
You should do authentication as you normally would and then use the Authorize attribute provided by SignalR to enforce the results of the authentication on the Hubs.
The Authorize attribute can be applied to an entire Hub or particular methods in the Hub. Some examples:
[Authorize] ā only authenticated users
[Authorize(Roles = "Admin,Manager")] ā only authenticated users in the specified .NET roles
[Authorize(Users = "user1,user2")] ā only authenticated users with the specified user names
You can also require all Hubs to require authentication by adding the following method in the Application_Start method:
GlobalHost.HubPipeline.RequireAuthentication();
Persistent Connections
You can use the user object in the request to see if the user is authenticated:
request.User.IsAuthenticated
I am currently working on an iPhone application. This application calls back to WCF services exposed through my ASP.NET web application. Currently, my WCF operation looks like the following:
[OperationContract]
[WebInvoke(Method = "POST")]
public string SubmitMessage(string message, int priority)
{
try
{
// Process message
// Return success code | message
}
catch (Exception)
{
// Return error code | message
}
}
My web application is using ASP.NET Forms Authentication. My challenge is, I only want authenticated users to be able to call this operation from their iPhone. I know that the iPhone SDK has baked in support for XML. However, Iām not sure how to lock down my WCF operation such that only authenticated users can access it.
How do I make my WCF operation only accessible to authenticated users from third party applications?
Thank you
This has to be done in both sides of the transfer, namely server (WCF site) and client (iPhones).
If you're using SOAP endpoints then you should look for Objective-C SOAP client libraries. This way all you will have to do is to setup best security options to your needs and your server-side code will be almost identical as it is at the moment.
Instead if you're exposing as RESTful endpoints I suggest you to look for an OpenID(&OAuth) approach. Here also, there are .NET and Objective-C libraries available. I belive this solution would require much more coding in both of the sides.
I am using a web service which sets the Thread.CurrentPrincipal object while logging in and soon later when another webmethod of the same web service accesses Thread.CurrentPrincipal, its different/resets
Can someone tell me if this is expected or can different webmethod calls from the same client can access the same Thread.CurrentPrincipal object
Thanks
As soon as you stop using a thread it goes back into the thread pool.
The next call will take a thread from the thread pool, but you have no control which one you get.
You need to send information about which user is making the call, with each request.
This is expected, every new web request is actually new thread. And every web request reset stuff like CurrentThread, CurrentCulture and so on.
What are you trying to do is authentication session. There are many possible solutions. But to suggest something I have to specify technology you use.
For example, ASP.NET ASMX Services can use Forms Authentication. Also they are aware about ASP.NET Session.
With WCF, you can enable ASP.NET support, so you will have same stuff like for ASP.NET ASMX Services. But you also can leverage on Windows Communication Foundation Authentication Service.
Anyways need more info from you.
If you are using the built-in ASP .NET authentication for your website and then just calling the web service from a web page, you may be able to enable session variables and user context information in the methods of the web service with a decoration. Like this:
[WebMethod(EnableSession=true)]
public void MyWebMethod()
{
string mySessionVar = HttpContext.Current.Session["sessionVar"].ToString();
IPrincipal currentUser = HttpContext.Current.User;
...
}
If that doesn't solve your problem, tell us what are you using the Thread.CurrentPrincipal object for (what you are pulling out of the Thread.CurrentPrincipal object). Perhaps there is another solution.
I am refactoring a working ASP.NET Web Application to expose Web Services interface using ASP.NET Web Service. According to Web Services authentication - best practices, Basic Auth over https is the way to go. Let's assume it is, as opposed to doing WS-Security, X509, etc..
On .NET 3.5/VS 2008, what's the simplest way of implementing custom http Basic Authentication (non-Windows account), for example, accepting only if user name is "foo" and password is "bar". Ultimately, I'd like Thread.CurrentPrincipal set.
Do I write my own HttpModule or can this be done simpler?
Likely using Custom Basic Authentication for IIS, written by Dominick Baier is the way to go. As he points out WCF 3.5's usernames over transport security cannot be used on IIS-hosted service, although my question was regarding ASP.NET Web Services not WCF.
There's another implementation of HTTP Module called Basic authentication in ASP.NET against custom datasource by Santosh Sahoo.
Although it's not what I wanted, I found QuickStart Tutorial's SOAP Headers sample to be informative workaround. Sending password in plain text over http is clearly insecure, but this example could be extended to add more security, for instance running on https or sending hash of "password + one-time GUID + timestamp".
Grab the value of the Authorization header, parse it and validate the username/password.
The value is username:password, encoded as a Base64 string.
See http://en.wikipedia.org/wiki/Basic_access_authentication for details.
Edit: if you want this done for every request, using the custom auth scheme, then it would be easier to write an HttpModule to handle parsing the header and setting the thread's principal.
If you are considering WCF, you can use usernameOverTransport security for basicHttpBinding. i.e. username and passowrd reside in the SOAP header of the request and all the traffic are protected by SSL encryption over the wire.
A custom UserNamePasswordValidator validator can be used to authenticate the incoming credentials against e.g. database.
You can set the thread principal within a custom IAuthorizationPolicy in the service behavior.
e.g. Evaluate method implementation for IAuthorizationPolicy for setting current principal
public bool Evaluate(EvaluationContext evaluationContext, ref object state)
{
Object obj;
if( evaluationContext.Properties.TryGetValue( "Identities", out obj ))
{
// get the authenticated identity
IIdentity client = (obj as IList<IIdentity>)[0];
evaluationContext.Properties["Principal"] = ... // create principal obj here for the identity
// this will set thread's current principal
}
return true;
}