I have a WCF service that is a relying party for a custom STS, built using WIF. My STS issues holder-of-key tokens to my client application. I have created a new 'backend' WCF service, that I need to call from the existing 'frontend' service. How can I use the incoming secure token in the frontend service to call the backend service, without retrieving a new one from the STS?
So far, in my frontend service, I have no problem accessing the incoming SamlSecurityToken using a custom Saml11SecurityTokenHandler.
After that, I tried two different ways to attach the out of band token to a service call on my target backend service:
Create a custom IssuedSecurityTokenProvider
Use ChannelFactoryOperations.CreateChannelWithIssuedToken
However, both of these attempts result in errors. From what I can tell, it seems to be the same dead end, - they do not accept the signed SamlSecurityToken. It seems that even though both of these methods accept the base SecurityToken class, they both only work if given a GenericXmlSecurityToken instance, instead of a SamlSecurityToken.
Update:
Here is a code sample and the exception details for bullet #1
Update 2:
After doing some more research, the closest thing I can find was an article about using Identity Delegation for WIF/ADFS which basically just uses ActAs tokens, in which the front end service would issue a request to the STS using the token it recieved from the client application. This would require an update to our custom STS, which we're hoping not to do at this time. I'm starting to wonder if the approach that I've illustrated in my diagram is even valid for WIF or WS-Trust?
As it turns out, the the concept of reusing an issued token by a front-end service to call a back-end service IS valid within the confines of WS-Trust protocol. However, for the vast majority of scenarios, it should not be considered a good practice. This is due to security and extensibility concerns. Security-wise, doing so would force both relying parties to use the same token encryption algorithms/keys, and also reduces your ability to authenticate the SAML token's audience restriction. This is exactly why WS-Trust was updated to support Identity Delegation with both ONBEHALFOF and ACTAS tokens. Utilizing either of these will help deal with this exact scenario in a more secure and robust way. It appears that the design of WIF's API follows this line of thinking, which explains why there is no direct API to be found for a front end service to reuse an incoming signed holder-of-key token to call a back-end service.
In conclusion, I have two answers to this question:
A. If you are the owner of your own custom-built STS, you can achieve this scenario outside of the default WIF/WCF pipeline, by following these steps:
In the client requestor application, manually retrieve the token from the STS using either WSTrustChannel or an IssuedSecurityTokenProvider. Notice that the token type will be GenericXmlSecurityToken, or some derivation of that.
Send the token, out-of-band, to the front end service. By out-of-band, I mean send it as an extra contract field, in a message header, or any other way.
Within the front end service, you can easily use the out-of-band token to call the back-end service by using ChannelFactory.CreateChannelWithIssuedToken() or by creating a custom IssuedSecurityTokenProvider. This is not possible when using an incoming bootstrap token, because WIF will always create a bootstrap token as a specific type, such as SamlSecurityToken. Both ChannelFactory and the IssueSecurityTokenProvider will only work with the GenericXmlSecurityToken!
B. Whether you have an out-of-box STS or a custom one, as long as it supports ActAs or OnBehalfOf, you can use proper Identity Delegation.
My conclusions are largely based on the following sources. I hope this ends up helping someone else with similar requirements.
http://www.cloudidentity.com/blog/2008/09/07/delegation-or-traversing-multilayer-architectures/
(Amazing explanation of ACTAS/ONBEHALFOF vs token reuse)
http://msdn.microsoft.com/en-us/library/ee748487.aspx (scroll down to find a comparison of ACTAS and BEHALFOF)
http://docs.oasis-open.org/ws-sx/ws-trust/v1.4/errata01/os/ws-trust-1.4-errata01-os-complete.html
(wstrust protocol, of course)
Related
A common use case for WebAPI would be to have shell views rendered by MVC controllers, which contain javascript that then hit your API to access data.
But let's say you have some expensive API operations and you don't want people remotely accessing those endpoints -- you only want your MVC views, delivered by your application, to access them. How could you go about protecting them?
In this case Request.IsLocal doesn't work, because javascript is invoking it from the client's browser on their machine. Even if it did work, you need to dig to get the real HttpContext in order to find this property -- and that solution wouldn't work in self-hosted WebAPI.
For API endpoints that require a valid IPrincipal, you could protect them with the [Authorize] attribute. But what about API endpoints that you want your app to be able to access for anonymous users?
I have tried a solution and will post it separately as an answer, because I'm not sure if it's the best (or even a good) approach.
If your MVC site uses authentication, you could enable forms authentication for your Web API methods. You could write a custom [Authorize] attribute that will check for the presence of a forms authentication cookie which will be sent from the AJAX call and if present construct the principal.
Another possible solution is to protect your API with tokens which is a more RESTful style. The idea here is that when a user authenticates on your MVC website you could generate and pass a token to the view which will be used when sending the AJAX request to the Web API which in turn will verify the validity of the token and its signature.
If on the other hand your site doesn't use authentication, then things will get very complicated because you have no way of knowing whether the request comes from a trusted client since you are using javascript to call your API methods.
Before you go harping about "what have you tried", here is what I have tried. It works. Just not sure if there is a better way.
Create an MVC action filter and add it as a global filter during Application_Start.
Create an Http (WebAPI) action filter and use it on actions that should reject remote requests.
The global MVC filter does this:
Looks for a specific cookie in the request. If the cookie is there, its value is decrypted. The decrypted value should be a string representation of a DateTime, so use DateTime.TryParse to get it out. If the value is correctly parsed to a DateTime, and that DateTime is less than a day old, STOP HERE and do nothing else.
If the cookie is not there, or cannot be decrypted / parsed, or is older than a day, write a new cookie to the browser. Use the current DateTime.UtcNow.ToString() as the value, encrypt it, and write it with HttpOnly = false.
The WebAPI filter does this:
Looks for a specific cookie in the request. If the cookie is there, decrypt its value and try to parse it out as a DateTime.
If the value is a valid DateTime and is less than 2 days old, STOP HERE and do nothing else.
Otherwise, throw a 403 Forbidden exception.
A couple of notes about my current implementation of this. First of all, I use AES encryption with a shared secret and a salt. The shared secret is stored as an appSetting in web.config. For the salt, I enabled anonymous identification and used Request.AnonymousID as the salt. I'm not entirely fond of the salt because it's tricker to get at in a WebAPI controller, but not impossible as long as it is not self-hosted.
I have a ServiceHost that implements many Contacts on various endpoints and bindings ((http & https) x (rest & soap) with Anonymous Access, Windows, or Custom authentication, as bound depending on the Contract) & nettcp with Windows authentication. Custom authentication is embedded in the http or soap headers. Each endpoint and contract has its purpose. It should all be manageable on a single ServiceHost - I don't want to split it up.
I've gotten it to the point where all the endpoints work and serve their content correctly, but the authentication/authorization isn't integrated into the WCF stack. I have been using a MessageInspector to handle validation of the authentication header and allowing it if the token was valid.
Now I want to integrate the authentication/authorization into the WCF stack. I want to be able to access the identity and check the claims in each Operation's implementation. And perhaps basic claims can be authorized centrally, like "are these claims authorizing anything at all in this contract?" (by contract type).
In the case of custom authentication, I have a signed/secure token that includes a custom implementation of identity and property claims which I can properly extract and convert into WCF claims upon receipt (even if I don't know exactly where to put them once I've got them). For Windows authentication, I just need access to the default Windows identity stuff.
I can set the ServiceAuthenticationManager and ServiceAuthorizationManager each to custom values, but it's not doing anything I want it to and I'm getting totally lost.
For example, the ReadOnlyCollection<IAuthorizationPolicy> authPolicy coming into Authenticate() seems to be inconsistent - sometimes it's empty, sometimes it has one UnconditionalPolicy and sometimes it has 2 or more (4?) of my custom IAuthorizationPolicy already there. Meanwhile IAuthorizationPolicy.Evaluate() gets executed anywhere from 0 to ~9 times per request. Sometimes, within IAuthorizationPolicy.Evaluate(), OperationContext.Current is null! And sometimes the evaluationContext.ClaimSets already has my claimset. Yet state is always null even when I give it a value in a previous enactment.
Rather than tackling these problems individually, I think it'd be better to step back and ask for some high-level explanation of what I should do/expect to see.
Authentication: When a request comes into the ServiceHost, it needs to get Authenticated. At this point in the pipeline, I don't need to know what they can do, just who they are. If a client submits both Windows credentials and a custom authentication ticket to a Contract/Binding on which I require just a custom authentication ticket, the service shouldn't be tricked into evaluating the wrong one. But perhaps at this stage in the WCF pipeline, the Contract hasn't been resolved so perhaps during this stage, all found identities/claims/tokens should be captured and selected among later. Is this right? How is this done?
Message Inspection: I have a custom MessageInspector which I'll still need for CORS support and OPTIONS request processing on some of the endpoints. I believe this happens after authentication and before authorization. In the case of OPTIONS, I set ref message to null and skip the Operation entirely, jumping straight to the BeforeSendReply. Clients don't send the auth-token on a CORS OPTIONS preflight request and so I allow these requests unconditionally.
Authorization: Depending on the Contract, I want to require certain authentication mechanisms and ignore others. I believe some setup needs to prepare the Thread Principal and Operation Context principal to the correct value. It seems that multiple Authorization policies can be in play at once. How do they interact?
Operation: I want to be able to implement each operation assuming that the identity of the caller is authenticated using a supported authentication (by Contract, which I'm OK maintaining hard-coded somewhere ONCE) and get the validated caller identity and assert simple permissions checks againsts the verified Claims.
How do I achieve this (code preferred over config xml)?
Thanks!
I have a ServiceStack service that uses WIF - internally everything works great - the ClaimsPrincipal & ClaimsIdentity objects get created, adding/reading claims from them is no problem at all.
However when i try to get this object from a client (tried ServiceStack client and c# WebRequest) it returns only a portion of the object - regardless if i have WIF installed on the client and attempt to cast. If i call directly and get the json result, this is all that is returned:
{"Principal":{"__type":"Microsoft.IdentityModel.Claims.ClaimsPrincipal, Microsoft.IdentityModel","Identity":{"__type":"Microsoft.IdentityModel.Claims.ClaimsIdentity, Microsoft.IdentityModel","Name":"BoogeyFace","AuthenticationType":"","IsAuthenticated":true}}}
How do i get the full WIF ClaimsPrincipal across the service boundary?
thanks :-)
To reuse issued token you have to configure your service to save bootstrap tokens.
This seams to be called save bootstrap context in .net 4.5.
This will give you access to your token in IClaimsIdentity.BootstrapToken property. See here for more details.
Having your original token on the service side allows You to communicate with another service just as if You were on a client.
For example You could use CreateChannelWithIssuedToken which is described here.
I'm now building a App that use asp.net webAPI on the server side,I got a problem about the validation:
I want to provide my webAPI for multi-platform,just like browser's javascript,or windows phone ,and so on,so I decide to implicit the validation with HTTP-BASIC,"(forgive my poor English),the problem is ,In the past time.
I always take some User's Information in SESSION,but we know that webAPI with RESTful-style is Session-stateless,so how to store the User's information:
And I get some idea,I hope you can help me to make the right choice,thx a lot
1.
put the information into the browser's cookie except the user's password and other important infos. everytime I make the http-request ,i take the cookies.and on the server-side,I can query the user's infomation.and make other steps.(the sequence will not work on moblie platform,cuz cookies only in browsers)
2.user HTTP-BASIC validation,and everytime the server get the httpRequest,it get the username and password in the HTTP-Headers,and server-side also can query the user's information.
Most REST APIs I've seen handle authentication one of two ways:
HTTP Headers, be it basic auth, or some custom headers to pass credentials. This would be your option 2. This is only really good if you're running over HTTPS, since the credentials will be in clear text in the headers.
Using a pair of tokens, one as an identifier (somewhat like a user name) and one shared secret between the client and the server (somewhat like a password). A hash is then made of the identifier, parts of the request parameters, and the secret. This hash and the identifier is then sent along with the request. The server, knowing the secret, then computes the hash using the same method, and ensures they match (Amazon Web Services uses this method, along with anything using OAuth).
More web APIs seem to be migrating to the second method here, as it is resistant to tampering and replay attacks, unlike basic auth. It is, of course, more complex.
RFC 5849 Section 3.4 for OAuth, while dry reading, goes through the process used for creating the hash, and probably would be a good starting point for implementing, if you desire. A basic implementation in C# is provided on the OAuth Google Code site, and might be a better choice to start with.
I'm trying to upgrade may program to support the new oAuth that Google uses in the AdWords.
I've my on-line part, which work fine, and get the access tokens (token, secret and consumer key).
My problem is when I try to make a soap request later with those credentials.
A. Which information do I need to save from the OnLine part? so far I save only the accessToken and the accessTokenSecret.
B. How do I use the accessToken, accessTokenSecret and what ever else I've saved in order to make a SOAP requests?
Some info on my process:
Not using the Client Library from Google (too much over head, and so far I didn't needed them)
Using the auto-generated code using VS2005 WSDL on the services I'm using.
C#
The problem is that what you're trying to do is a bit involved. It's got more to do with the oAuth process itself than the AdWords API implementation. I think that this is a case where it would be very beneficial to use the client library.
You actually need to use your token and consumer key to sign the request. This can either be done using RSA-SHA1 or RSA-HMAC; in the first instance you sign it with a private key file and upload the public key to Google; for RSA-HMAC you just use the token and consumer secrets instead of the public/private key.
You can find out more about doing this here, but I would recommend just using Google's implementation unless you're interested in the internals of oAuth. I tried it myself a while ago and found it quite complicated.