These approaches are non-standard both because they well… don’t utilize the large body of standards that exist for web service security and because they are outside of what would probably be considered best practices by most people in the industry.
Custom Security Headers
It is fairly common to see people develop services that require authentication through a custom security header.
Now, if your service will consume a token that is truly custom, which is to say outside the standard token types defined in the WSS specs, then this is a perfectly reasonable approach. A good example of this would be a service that can consume a web SSO token from Oracle Access Manager.
This approach is especially powerful if your service can consume the custom token plus one or more of the standard tokens. One example would be a service setup to consume the Oracle Access Manager cookie or a standard username token.
However, one mistake you often see people make is to hard code in a required custom security header that is in essence the same as one of the standard WSS authentication methods. Usually, it is a custom security header that just holds a username and password, which makes it equivalent to the WSS username token.
There are several reasons developers take this approach but they mostly center on not understanding the flexibility and value of the security functionality that is already built into the container that is running their service. For example, sometimes developers will say that they need a custom token since the container will only compare the username in username token to the UID attribute in the directory, which is simply not the case.
Even if custom handling of authentication is required, it is still better to utilize a standard token (with custom handling) over a custom token.
Another mistake you see people make is once they decide they need a custom token, they will just turn off security at the container level and process the token inside of their service. It is far better for custom authentication code to live inside of the container than in the service itself. Staying with the container for security will:
- Allow you to easily use your custom token with other services
- Allow you to switch to a standard authentication method down the road
- Keep you compatible with authorization and auditing done at the container level which you may want to keep even if you need to do custom authentication.
- Use of standard authentication tokens that are processed by the container’s out-of-the-box functionality.
- Use of standard authentication tokens that are processed by custom code in the container.
- Use of custom authentication tokens/headers that are processed by custom code in the container.
- Use of custom authentication tokens/headers that are processed by code in the service itself.
The second approach I’d like to discuss is specific to propagating an identity from a web app or service to a “downstream” service. The approach is simply to stick the user identity into the body of the request and consume it with custom code in the service. Now obviously, this approach is inherently insecure on its own, but it is an appropriate option in situations where the client of the service can be trusted. Usually this trust will be justified by the security that is present at the transport or network level.
Sticking a user identity into the body of the request is really analogous to use of the SAML bearer confirmation method which I discussed in my first post on this blog.
So, it is probably most useful to think of its appropriateness in the same terms. In the blog post on the bearer confirmation method I discussed some advantages that it had over just sticking the user identity into the request body. Now, I’d like to turn the table and look at some possible advantages putting the identity in the request body sometimes has over SAML with bearer and over creating a custom security header of a similar ilk.
Now, you are probably saying to yourself: Hold on Brian, you just laid out a hierarchy with using standards and container functionality at the top and custom approaches executed in the service code at the bottom.
Well that is true, but there is a reason that putting the identity in the request body and extracting it in the service should sometimes be considered. The main problem with SAML with the bearer confirmation method is a lack of support for it. This lack of support applies not only to server side WSS stacks but, perhaps even more importantly client side stacks. If you are creating a service that may be widely consumed and are operating in a very heterogeneous environment where client side developers maybe be using any number of different software packages for their development, then SAML with bearer may be the wrong choice for you. Likewise, it may be harder for consumers of your service to create a custom security header than to just stick the identity in the request body. Along similar lines, it may be easier to convey the format you want to use for the user identity in the WSDL if the identity is being put in the body.
The final consideration for whether propagating the identity in the request body is a good way to go centers on how many services you might have where such trusted identity propagation is deemed as acceptable. If you have a huge SOA infrastructure with tons of applications consuming tons of internal services then it probably makes sense to standardize on bearer or develop a custom security header and corresponding container plug-in to consume the header.
However, if you only have one service that fits this description and SAML with bearer isn’t supported by your stack, then it may be hard to justify the added effort of developing a custom token. In that case, just sticking the user identity in the request body may be the best way to go.