Showing posts with label ws-security. Show all posts
Showing posts with label ws-security. Show all posts

Tuesday, September 25, 2012

Attaching OWSM policies to JRF-based web services clients

I've recently came across a question in one of our internal mailing lists where a person was under the impression that he would have to write code to propagate the identity when making a web service call using OWSM policies. My answer was something like: "depending on the type of your client you may have to write some very small piece of code to attach a policy, but you should not write code at all to either retrieve the executing client identity or to do the propagation itself". Fortunately, I had an unpublished article that applied 100% to his use case. And here it is now (a little bit revamped).

OWSM (Oracle Web Services Manager) is Oracle's recommended method for securing SOAP web services. It provides agents that encapsulate the necessary logic to interact with the underlying software stack   on both service and client sides. Such agents have their behavior driven by policies. OWSM ships with a bunch of policies that are adequate to most common real world scenarios.

Applying policies to services and clients is usually a straightforward task and can be accomplished in different ways. This is well described in the OWSM Administrators Guide. Looking from the client perspective, the docs describe how to attach policies to SOA references, connection-based clients (typically ADF-based clients) and standard Java EE-based clients using either Enterprise Manager or wlst.

Oracle FMW components (like OWSM agents) are typically deployed on top of a thin software layer called JRF (Java Required Files), providing for the required interoperability with software stacks from different vendors.

This post is a step-by step showing how to code a JRF-based client and attach OWSM policies to it at development-time using Oracle JDeveloper.

Tuesday, November 15, 2011

Oracle Secure Token Services 101

In this post I want to introduce our readers to the Oracle Secure Token Service (OSTS) product, Oracle’s solution for providing standards-based mechanisms for trust brokerage across different identity domains. I won’t cover the gory details in this first post, but I expect to give you a good overview on what the product is, the typical usage scenarios and a basic understanding of its main concepts.

OSTS facilitates secure communications between web services providers and consumers. In OSTS terminology, a web service provider is a Relying Party, while a web service consumer is a Requester. It works as a central hub where web services consumers come and get security tokens that are further propagated to web services providers. In this way, it frees clients from all the necessary infrastructure to generate tokens required for identity propagation. Whenever the client needs a token, it requests one from OSTS.

It’s important to make clear that OSTS is no security PEP (Policy Enforcement Point) for web services. This is up to other products like OWSM (Oracle Web Services Manager) and OEG (Oracle Enterprise Gateway). It can actually be used with both of them. OEG, for example, can act as an OSTS client when protecting web services. OSTS is a set of services that validate incoming token requests and issue security tokens. It does, however, check whether a Requester can ask for a token to access a Relying Party, but it stops right there.

OSTS supports both WS-Security and WS-Trust as the protocols for token transport.

Monday, January 3, 2011

How do I secure my services?

I've been up early for a couple of days talking to a customer about how they should secure their services.

We started with the bit of advice "only make them as secure as you need to". In other words the "HelloWorld" service probably doesn't need an encrypted request with a signed SAML Assertion over a mutually authenticated SSL channel on a private, physically disconnected network segment. And the "launch nuclear weapon" service should probably be secured with something other than a simple username token.

Figuring out what sort of security your services require takes time and effort and lots of information. So I'm not going even try to give you a recommendation here. Instead I guess I'm going to tell you what I told them...

This customer has requests coming in from the Internet. Their users do NOT have individual certificates but do have a username and password. The plan, in as much as there is one, is to have OSB in the DMZ accept the SOAP request from the user and then route it to the real service behind the firewall. So the customer asked us what they should do to secure the services.

They tossed around a bunch of ideas including:

  • using an STS - the client would go to the STS and get a SAML assertion, then use that assertion to send the request to OSB.
  • using an STS with WS-Secure Conversation - same as above, but instead of just getting a SAML Assertion the client would do the more advanced session "stuff" that spec describes.
  • Publishing a certificate issuance SOAP endpoint. The SOAP client would call over to that service with a username and password and get a Certificate issued. The username and password would then be locked out and the Certificate would be the only way the user could authenticate after that point.
All of these solutions work - that is to say that they all provide some aspects of security and thus make the service more secure in some way. But they're all a bit heavy handed and require quite a bit of smarts on the client side. So we had a conversation about what they were actually trying to accomplish.

Turns out their requirements were that the data had to be transmitted securely - meaning nobody else could listen in and see the data. And they wanted to make sure that nobody could inject requests that didn't come from a real user into the flow. And that's it.

Those of you playing along at home know that one way SSL with the username and password in a WS-Security header meets those requirements. Plus it's really lightweight and simple to implement.

Sometimes simpler is better. And in this case turning all of the security levers up to 10 wouldn't have bought them anything but trouble.

So that's what they're going to go with - at least initially. In the future they'll revisit this solution and if things change they can always add new Proxy Services on the bus for other authentication methods.


Behind the bus was a whole 'nother story. They're going to use SAML assertions with the Sender Vouches confirmation method to pass identity down to the real services. But that's a story for another day.

Wednesday, June 16, 2010

Do I Need to Secure My Service?

I sometimes get asked by customers whether they need any security at all for their “internal services”. I wanted to take a post to examine this subject.

Let’s take the simplest case possible from a security vantage point: a synchronous web service being called from a limited number of trusted internal clients (let’s say web applications). Because the web service is synchronous we don’t have to worry about the request sitting in a queue unprotected. Likewise, because the web service is being called from a limited number of internal clients we might be inclined to care less, if at all, about ensuring that users/clients are authorized to call the service. Finally, we will assume that there is no requirement to authenticate a “user” of the client invoking the service.

At the same time we will assume that the service is a “high value” service such that exposing it to the “outside” without security would be a mistake.

So, does such a service need security?

I think to answer this question we have to look at all the possible security concerns for such a service and how they can be addressed with or without explicit security. Usually, when a customer implies that their service doesn’t mean security what they are really saying is that the boundaries of their physical network providing all the security they need. So, let’s look and see to what extent that may be true.

The security concerns for an internal, synchronous service are as follows:

1) Client trust: ensuring that only authorized users/clients are invoking the service.

There are two types of potentially unauthorized clients to worry about, internal clients and external clients.

To protect against external client access physical network boundaries may be sufficient.
However, in my experience an increasing number of customers are not comfortable relying on their physical network.

Without additional security, the only protection against unauthorized internal access to your services is the trust and good will of the users that have access internally.

Two-way SSL is a straight forward, easy to deploy security solution that you can add to your web service that provides strong protection against all types of unauthorized client access. Note though, that one-way SSL does nothing to help with this case.

2) Service trust: ensuring that the service being invoked by consumers of the service is authentic; that it is not a Trojan horse service.

The physical network does provide some level of protection here in that a malicious Trojan service would have to be accompanied by IP address spoofing or DNS hacking to do damage. The greater danger might be the standing up and advertising of an unauthorized service for a SOA phishing attack.

Here SSL (technically just one-way) can help ensure that only authorized services are being called by clients.

3) Message integrity: ensuring the message has not been tampered with.

The physical network can limit the potential for capture, alter, and replay attacks to internal users but SSL can be added to eliminate all risk associated with capturing messages over the wire.

4) Message confidentiality: ensuring that the information in the message cannot be intercepted and read.

The physical network can limit the potential for message capture to internal users but SSL can be used to eliminate all risk of capture over the wire.

5) Tracking and reporting: ensuring that the ability exists to track specific requests/transactions to a specific user/client.

Without additional steps the only tracking mechanism provided by the physical network is the IP address of the client which may or may not be of use.

When you add 2-way SSL with each client getting a unique client certificate, you now have definitive record of which client made which request.

6) Identity propagation
If there is a requirement to propagate the identity of the user of a web application onto the web service then there is potentially additional security required.

Given the assumptions made at the beginning that the consumers of our service are trusted internal clients, we will assume that we can trust them to propagate whatever identity they want. Still, the propagation has to be done in some fashion.

Here we have 3 options:
1) The identity could be added through a custom HTTP header. This is easy on the client and secure if we trust the client and are using 2-way SSL at the transport (the header can be encrypted with symmetric cryptography for added security). On the downside it is very non-standard and will most likely require some custom work on the service side to accept an identity from a custom header.

2) The use of a real WSS Security header such as a SAML assertion. Using SAML with the bearer confirmation method (http://fusionsecurity.blogspot.com/2009/09/bearer-confirmation-method-huh-what-is.html) provides a more standard way of propagating a user identity. With bearer, no messy signing or encryption is required and given our assumptions the security of bearer is probably sufficient if 2-way SSL is being used. The only gotcha is you have to have client and server side stacks that can both “speak” SAML bearer.

3) Many customers ask/talk about just putting the user identity in the body of the message. In many ways this is the easiest thing to do. I also think it makes sense if the business logic of the service will actually make use of the user identity information; as would be the case for a “process insurance selection” or “purchase ticket” service. The only thing to understand is that putting user identity information in the message body means including it in the schema and explicitly coding how to retrieve it in the service. If you rely on WSS security for user propagation then the user identity can be left out of the schema and the service can be coded just to get the identity from the container.

When identity propagation comes up in these conversations, the discussion usually centers on using SAML vs. just putting the user info in the message body. The key deciding factors here are whether the user info will be used by the business logic of the service, whether you want to include the user info in the schema or not, and whether you are comfortable with the code of the service itself retrieving the user identity from the message or whether you’d rather rely on getting the user identity from the container.

Summary
On a very restrictive physical network where trust in the users that have access to the network is very high, it may be OK to deploy a high value web service without additional security. However, most of the time it is a good idea to utilize 2-way SSL to provide strong transport level security.
If identity propagation is required a judgment call needs to be made on how to propagate the identity and whether or not to do so through transport security, WSS message level security, or just in the body of the message.

Monday, November 30, 2009

Problems with Unsigned WS-Security Timestamps in the Response

I've had a few customers recently that have struggled with this scenario - a web-service consumer receives a response message that it cannot validate. We spend some much time focusing on the request, but often don't think about the response. The messages in question look something like this:


<?xml version='1.0' encoding='UTF-8'?>
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
<S:Header>
<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" S:mustUnderstand="1">
<wsu:Timestamp xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<wsu:Created>2009-11-03T10:12:44Z</wsu:Created><wsu:Expires>2009-11-03T10:13:44Z</wsu:Expires></wsu:Timestamp>
</wsse:Security>
</S:Header>
<S:Body>
<ns2:sayHelloResponse xmlns:ns2="http://ws.my/">
<return>
Hello,Josh!
</return>
</ns2:sayHelloResponse>
</S:Body>
</S:Envelope>


The issue is that the message includes a timestamp, but its not signed. I've seen this issue with both WCF clients as well as Oracle Web Services Manager (OWSM).

Depending on the client stack, there are two ways to fix this issue. The first is to simply sign the response. This is really the best practice, especially for a message that the sender took the time and effort to add WS-Security to in the first place. The second approach, is to simply remove the message security (i.e. WS-Security header and timestamp). For example, below is a modified Wssp1. 2-2007-Https.xml that still ensures that the request is over SSL, but removes the "offending" timestamp.

Wssp1. 2-2007-Https-no-timestamp.xml



<?xml version="1.0"?>
<wsp:Policy
xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy"
xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702"
>
<sp:TransportBinding>
<wsp:Policy>
<sp:TransportToken>
<wsp:Policy>
<sp:HttpsToken />
</wsp:Policy>
</sp:TransportToken>
<sp:AlgorithmSuite>
<wsp:Policy>
<sp:Basic256/>
</wsp:Policy>
</sp:AlgorithmSuite>
<sp:Layout>
<wsp:Policy>
<sp:Lax/>
</wsp:Policy>
</sp:Layout>
</wsp:Policy>
</sp:TransportBinding>
</wsp:Policy>

Friday, November 6, 2009

The new Oracle Entitlements Server (OES) and Oracle Web Services Manager (OWSM) 11g integration is finally here!

I know that a lot of people have been after me for this, so I want to apologize again for how long it has taken me to get this together (OOW + 3 weeks). But I hope people find it worth the wait.

This is essentially an update of some work that Kamlesh Patel did last year, so the basic design is really his idea.

OES-OWSM Integration FAQ


Question:Where can I get it?

Answer: I added to the OWSM 11g Custom Assertions Project on www.samplecode.oracle.com.

Question:What are the prerequisites?

Answer: You'll need an 11g SOA Suite Domain protected by an OES WLS SM. What I did for the OOW demo that makes things a lot simpler is use the OESAdjudicator. I talked a little about this approach previously. Basically, follow the steps I outline before except that instead of throwing the domain into discovery mode and figuring out the WLS resources, just add the OESAdjudicator to the domain. This basically eliminates the need for OES to protect the WLS resources.

Question: How do I build it?
Answer: You'll need to get the source code from svn. The details are here.
The src and the build are contained in the oes-owsm directory. You'll need to modify the build.xml file to point to the SOA home and OES home directories. From there, set-up you're environment (BEA_HOME/wlserver_10.3/server/bin/setWLSEnv.cmd) and then run ant. You should end-up with a file called oes-owsm.jar.

Question:Why do I need to know how to build it?

Answer:Because when you use it to protect a WLS Web Service, all of the configuration is contained in the META-INF/policies/samples/oes file, and this needs to be packed into the jar. I have not tested this custom assertion protecting SOA Composite Web Services

Question: What can I configure in the META-INF/policies/samples/oes file?

Answer: Let's take a look at the file



<wsp:Policy xmlns="http://schemas.xmlsoap.org/ws/2004/09/policy" xmlns:orasp="http://schemas.oracle.com/ws/2006/01/securitypolicy"
orawsp:status="enabled" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" orawsp:category="security" orawsp:attachTo="binding.server" wsu:Id="oes_authorization_policy"
xmlns:orawsp="http://schemas.oracle.com/ws/2006/01/policy" xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy"
wsp:Name="sample/oes">

<orasp:oes orawsp:Silent="true" orawsp:Enforced="true" orawsp:name="OES Authorization" orawsp:category="security/authorization">
<orawsp:bindings>
<orawsp:Implementation>com.oracle.oes.owsm.sample.Assertion</orawsp:Implementation>
<orawsp:Config orawsp:name="oes" orawsp:configType="declarative">
<orawsp:PropertySet orawsp:name="OES RMI SSM Settings">
<orawsp:Property orawsp:name="ConfigDirectory" orawsp:type="string" orawsp:contentType="required">
<orawsp:Value>c:/bea/ales32-admin/rmi-ssm/instance/rmissm/pdpproxy</orawsp:Value>
</orawsp:Property>
<orawsp:Property orawsp:name="ConfigID" orawsp:type="string" orawsp:contentType="required">
<orawsp:Value>soa_suite_domain2</orawsp:Value>
</orawsp:Property>
<orawsp:Property orawsp:name="AuthenticationRequired" orawsp:type="boolean" orawsp:contentType="required">
<orawsp:Value>false</orawsp:Value>
</orawsp:Property>
</orawsp:PropertySet>
<orawsp:PropertySet orawsp:name="OES Identity Assertion Settings">
<orawsp:Property orawsp:name="InternalAssertion" orawsp:type="boolean" orawsp:contentType="required">
<orawsp:Value>false</orawsp:Value>
</orawsp:Property>
<orawsp:Property orawsp:name="OWSMIdentity" orawsp:type="string" orawsp:contentType="required">
<orawsp:Value>OWSM</orawsp:Value>
</orawsp:Property>
</orawsp:PropertySet>
<orawsp:PropertySet orawsp:name="OES Authorization Settings">
<orawsp:Property orawsp:name="Application" orawsp:type="string" orawsp:contentType="required">
<orawsp:Value>owsm</orawsp:Value>
</orawsp:Property>
<orawsp:Property orawsp:name="Resource" orawsp:type="string" orawsp:contentType="required">
<orawsp:Value>oow2009demo</orawsp:Value>
</orawsp:Property>
<orawsp:Property orawsp:name="LookupAction" orawsp:type="string" orawsp:contentType="required">
<orawsp:Value>lookup</orawsp:Value>
</orawsp:Property>
<orawsp:Property orawsp:name="ExecuteAction" orawsp:type="string" orawsp:contentType="required">
<orawsp:Value>execute</orawsp:Value>
</orawsp:Property>
</orawsp:PropertySet>
</orawsp:Config>
</orawsp:bindings>
</orasp:oes>
</wsp:Policy>

There are only a few properties that you need to really care about. ConfigID is the name of the realm that WLS is running - I think the configTool makes it the domain name, but look in config.xml just to be sure. Application and Resource are concatenated together to make up the prefix for the resource in OES. Example: //app/policy//owsm/oow2009/model object name/port name

Question: How do I install it?

Answer: Copy the oes-owsm.jar to the DOMAIN_HOME/lib directory, and restart the server.

Question: How do I bind it to a webservice?

Answer: You add it to policy just like any other WLS Web-Services policy. Either through the WLS console or through the @Policy annotation. Note: You need to configure an additional policy that does the actual authentication, like one of the SAML policies. The assertion assumes that the user is already authenticated. Also, again I haven't tested it attaching it to a SOA composite, but if some one wants to try, I'll support the effort ;)

Question: How do I author an OES policy using it?
Answer: Take a look at the policies from my OOW demo



I modeled it as a two step process (I could have just as easily passed down the entire SOAP message to the WLS SM, like I did in the OES-BPEL integration, but I think for most in-bound authorization cases, I like this model). In the first step, the assertion calls OES with the lookup action. If it succeeds, it processes the responses in an interesting way. If the response has a name of namespace then it sets uses it as the target name space for the XPathQuery. If its anything else, then the Assertion assumes that the name of the response is a dynamic attribute, and the value is an XPathQuery that the assertion should run to populate the attributes.

In the example for OOW, there are two responses from the lookup. One to get the value of the CCType in the body and add it to the variable oow_cc_type. The other is pulling the value of the attribute title from the AttributeStatement from the SAML Assertion (basically, the user's title) and sets it in the oow_title attribute.

The execute action gets called next and basically, as you can see from the example, passes in the values it got from the lookup XPATHQuery.

Question: What do I do if I want to use a namespace other than tns,env, or saml?

Answer: You need to add it to modify the AssertionNamespaceContext.java to handle the namespace. The code is pretty simple.



public String getNamespaceURI(String prefix) {
System.out.println("Looking for the namespace for prefix: "+prefix);

if (prefix.equals("env")) {

return "http://schemas.xmlsoap.org/soap/envelope/";

} else if (prefix.equals("saml")) {

return "urn:oasis:names:tc:SAML:1.0:assertion";

}

return theNamespace;
}

So What Next?


I added the project (like most of my stuff from the blog) to http://soa-security.samplecode.oracle.com. Try this out, and let me know what you think, but also, this integration could be enhanced in a number of ways. Examples:

  • What should OES do when filtering the response?
  • What could OES do with responses if it knew that the Web Service has a DataControl (i.e. SOAP Message contains a query)?

The source is out there, so I'm hoping people will add their own contributions. Basically, I hope that I've taught you how to fish. If you are starving, just post a comment here, and we'll throw you a fish stick :)

Wednesday, November 4, 2009

WebLogic Server (WLS) to Oracle Service Bus (OSB) to WebLogic Server using SAML Sender Vouches - Active/Active

In yesterday's post on WLS to OSB to WLS with SAML Sender Vouches, OSB was not really acting as a full "active-intermediary". Basically, OSB was validating the SAML Assertion on the request and sending a new request with a new SAML Assertion to the business-service. The response from the business service (though signed) was ignored by OSB. The signature is validated by the sender. Let's for the sake of discussion call this configuration active/passive security. This model works if:

  • You are basically interesting in using OSB to authorize the use of services
  • You are not doing any transformations on the response (you'll break the signature).
  • The producer and consumer trust each other directly. This is different then they each trust the service bus.


If your deployment meets this criteria, then "Bob's Your Uncle" (I'm from Massachusetts, not California, so I'm not sure I used that right - but basically I'm saying "you're good")

If not, then read on. These are the gory details of getting this scenario to work in active/active. I'm not going to cover everything from yesterday, I'll just get down to the brass tacks of the policies.

Direction.In (Request)



Direction.Out (Response)



Configuring the WLS Service Producer


Since this is a use case primarily about processing the response, let's start with the response coming back from the service producer. OSB cannot handle <ProtectTokens> policy assertions because it does not support the STR Transform that WLS uses to generate the signature. So, this assertion has to be removed from the standard Wssp1.2-2007-Saml1.1-SenderVouches-Wss1.0.xml.

Configuring the Business Service


A nuance of the way that OSB enforces policy is that the entire message is processed - signatures validated, messages decrypted - and then the policy is checked to see if it complies. The policy is basically a minimum that has to be met - not a prescription for how to validate the message. The idea of the "Empty" policy is to just have OSB process the signature that the Service Producer generated. There are no other conditions.

Configuring the Proxy Service


The message now needs to be signed by OSB. The pre-configured Sign.xml will work just fine.

Configuring WLS Service Consumer


You need to use two different policies for the JAX-WS client. Since the signature generated by OSB does not conform with the standard policy in two ways - it does not protect the tokens (sign) and it does include the RAW X.509 Certificate as opposed to an reference by Issuer Serial Number. So, the policy for the outputMessage (outbound) is a custom policy very similar to the in-bound policy on the service consumner, except that we have to additionally allow for the Recipient Token to be passed. The policy for the inputMessage (inbound) is the standard Wssp1.2-2007-Saml1.1-SenderVouches-Wss1.0.xml. The code looks like this:


ClientPolicyFeature cpf =
new ClientPolicyFeature();

InputStreamPolicySource ps_out = new InputStreamPolicySource(this.getServletContext().getResourceAsStream("/WEB-INF/policy-no-protect-plus-recipient-token.xml"));
InputStreamPolicySource ps_in = new InputStreamPolicySource(this.getServletContext().getResourceAsStream("/WEB-INF/policy.xml"));

cpf.setEffectivePolicyForInputMessage(ps_in);
cpf.setEffectivePolicyForOutputMessage(ps_out);

Dispatch<SOAPMessage> dispatch = service.createDispatch(portName,
SOAPMessage.class, Service.Mode.MESSAGE, new WebServiceFeature[] {cpf});



SOAPMessage response = dispatch.invoke(request);


Policies


Wssp1.2-2007-Saml1.1-SenderVouches-Wss1.0.xml minus ProtectTokens



<?xml version="1.0" encoding="windows-1252" ?>
<wsp:Policy wssutil:Id="Wssp1.2-2007-Saml1.1-SenderVouches-Wss1.0.xml" xmlns:wssutil="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy">
<ns1:AsymmetricBinding xmlns:ns1="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
<wsp:Policy>
<ns1:InitiatorToken>
<wsp:Policy>
<ns1:X509Token ns1:IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/AlwaysToRecipient">
<wsp:Policy>
<ns1:WssX509V3Token10 />
</wsp:Policy>
</ns1:X509Token>
</wsp:Policy>
</ns1:InitiatorToken>
<ns1:RecipientToken>
<wsp:Policy>
<ns1:X509Token ns1:IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/Never">

<wsp:Policy>
<ns1:WssX509V3Token10 />
</wsp:Policy>
</ns1:X509Token>
</wsp:Policy>
</ns1:RecipientToken>
<ns1:AlgorithmSuite>
<wsp:Policy>
<ns1:Basic256 />
</wsp:Policy>
</ns1:AlgorithmSuite>
<ns1:Layout>
<wsp:Policy>
<ns1:Lax />
</wsp:Policy>
</ns1:Layout>
<ns1:IncludeTimestamp />

<!-- OSB does not work well with this assertion
<ns1:ProtectTokens />
-->

<ns1:OnlySignEntireHeadersAndBody />
</wsp:Policy>
</ns1:AsymmetricBinding>
<ns2:SignedSupportingTokens xmlns:ns2="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
<wsp:Policy>
<ns2:SamlToken ns2:IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/AlwaysToRecipient">
<wsp:Policy>
<ns2:WssSamlV11Token10 />
</wsp:Policy>
</ns2:SamlToken>
</wsp:Policy>
</ns2:SignedSupportingTokens>
<ns3:Wss10 xmlns:ns3="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
<wsp:Policy>
<ns3:MustSupportRefKeyIdentifier />
<ns3:MustSupportRefIssuerSerial />

</wsp:Policy>
</ns3:Wss10>
</wsp:Policy>


Wssp1.2-2007-Saml1.1-SenderVouches-Wss1.0.xml minus ProtectTokens plus Include Recipient Token



<?xml version="1.0" encoding="windows-1252" ?>
<wsp:Policy wssutil:Id="Wssp1.2-2007-Saml1.1-SenderVouches-Wss1.0.xml" xmlns:wssutil="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy">
<ns1:AsymmetricBinding xmlns:ns1="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
<wsp:Policy>
<ns1:InitiatorToken>
<wsp:Policy>
<ns1:X509Token ns1:IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/AlwaysToRecipient">
<wsp:Policy>
<ns1:WssX509V3Token10 />
</wsp:Policy>
</ns1:X509Token>
</wsp:Policy>
</ns1:InitiatorToken>
<ns1:RecipientToken>
<wsp:Policy>
<ns1:X509Token ns1:IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/AlwaysToInitiator">

<wsp:Policy>
<ns1:WssX509V3Token10 />
</wsp:Policy>
</ns1:X509Token>
</wsp:Policy>
</ns1:RecipientToken>
<ns1:AlgorithmSuite>
<wsp:Policy>
<ns1:Basic256 />
</wsp:Policy>
</ns1:AlgorithmSuite>
<ns1:Layout>
<wsp:Policy>
<ns1:Lax />
</wsp:Policy>
</ns1:Layout>
<ns1:IncludeTimestamp />

<!-- OSB does not work well with this assertion
<ns1:ProtectTokens />
-->

<ns1:OnlySignEntireHeadersAndBody />
</wsp:Policy>
</ns1:AsymmetricBinding>
<ns2:SignedSupportingTokens xmlns:ns2="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
<wsp:Policy>
<ns2:SamlToken ns2:IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/AlwaysToRecipient">
<wsp:Policy>
<ns2:WssSamlV11Token10 />
</wsp:Policy>
</ns2:SamlToken>
</wsp:Policy>
</ns2:SignedSupportingTokens>
<ns3:Wss10 xmlns:ns3="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
<wsp:Policy>
<ns3:MustSupportRefKeyIdentifier />
<ns3:MustSupportRefIssuerSerial />

</wsp:Policy>
</ns3:Wss10>
</wsp:Policy>




Empty Policy



<?xml version="1.0"?>

<wsp:Policy
xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy"
xmlns:wssp="http://www.bea.com/wls90/security/policy"
xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
xmlns:wls="http://www.bea.com/wls90/security/policy/wsee#part"
wsu:Id="validate-bs-response"
>


<wssp:MessageAge/>

</wsp:Policy>

Sender Vouches plus Sign Timestamp



<?xml version="1.0"?>

<wsp:Policy
xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy"
xmlns:wssp="http://www.bea.com/wls90/security/policy"
xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
xmlns:wls="http://www.bea.com/wls90/security/policy/wsee#part"
wsu:Id="saml-policy-to-business-service"
>

<wssp:Identity>
<wssp:SupportedTokens>
<wssp:SecurityToken TokenType="http://docs.oasis-open.org/wss/2004/01/oasis-2004-01-saml-token-profile-1.0#SAMLAssertionID">
<wssp:Claims>
<wssp:ConfirmationMethod>sender-vouches</wssp:ConfirmationMethod>
</wssp:Claims>
</wssp:SecurityToken>
</wssp:SupportedTokens>
</wssp:Identity>

<wssp:Integrity>

<wssp:SignatureAlgorithm URI="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
<wssp:CanonicalizationAlgorithm
URI="http://www.w3.org/2001/10/xml-exc-c14n#"/>

<wssp:Target>
<wssp:DigestAlgorithm
URI="http://www.w3.org/2000/09/xmldsig#sha1" />
<wssp:MessageParts
Dialect="http://schemas.xmlsoap.org/2002/12/wsse#part">
wsp:Body()
</wssp:MessageParts>
</wssp:Target>

<wssp:Target>
<wssp:DigestAlgorithm
URI="http://www.w3.org/2000/09/xmldsig#sha1" />
<wssp:MessageParts
Dialect="http://www.w3.org/TR/1999/REC-xpath-19991116">
wsp:GetHeader(./wsse:Security/wsu:Timestamp)
</wssp:MessageParts>
</wssp:Target>

<wssp:Target>
<wssp:DigestAlgorithm URI="http://www.w3.org/2000/09/xmldsig#sha1" />
<wssp:MessageParts
Dialect="http://www.bea.com/wls90/security/policy/wsee#part">
wls:SecurityHeader(Assertion)
</wssp:MessageParts>
</wssp:Target>

</wssp:Integrity>

<!--
<wssp:Confidentiality>

<wssp:KeyWrappingAlgorithm URI="http://www.w3.org/2001/04/xmlenc#rsa-1_5"/>

<wssp:Target>
<wssp:EncryptionAlgorithm
URI="http://www.w3.org/2001/04/xmlenc#tripledes-cbc"/>
<wssp:MessageParts
Dialect="http://www.bea.com/wls90/security/policy/wsee#part">
wls:SecurityHeader(Assertion)
</wssp:MessageParts>
</wssp:Target>

<wssp:Target>
<wssp:EncryptionAlgorithm
URI="http://www.w3.org/2001/04/xmlenc#tripledes-cbc"/>
<wssp:MessageParts
Dialect="http://schemas.xmlsoap.org/2002/12/wsse#part">
wsp:Body()</wssp:MessageParts>
</wssp:Target>

<wssp:KeyInfo />
</wssp:Confidentiality>
-->

<wssp:MessageAge/>

</wsp:Policy>

<wssp:MessageAge/>

</wsp:Policy>

Standard OSB SAML Sender Vouches



<?xml version="1.0"?>

<wsp:Policy
xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy"
xmlns:wssp="http://www.bea.com/wls90/security/policy"
xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
xmlns:wls="http://www.bea.com/wls90/security/policy/wsee#part"
wsu:Id="saml-policy"
>

<wssp:Identity>
<wssp:SupportedTokens>
<wssp:SecurityToken TokenType="http://docs.oasis-open.org/wss/2004/01/oasis-2004-01-saml-token-profile-1.0#SAMLAssertionID">
<wssp:Claims>
<wssp:ConfirmationMethod>sender-vouches</wssp:ConfirmationMethod>
</wssp:Claims>
</wssp:SecurityToken>
<!--
<wssp:SecurityToken TokenType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3"/>
-->
</wssp:SupportedTokens>
</wssp:Identity>

<wssp:Integrity>

<wssp:SignatureAlgorithm URI="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
<wssp:CanonicalizationAlgorithm
URI="http://www.w3.org/2001/10/xml-exc-c14n#"/>

<wssp:Target>
<wssp:DigestAlgorithm
URI="http://www.w3.org/2000/09/xmldsig#sha1" />
<wssp:MessageParts
Dialect="http://schemas.xmlsoap.org/2002/12/wsse#part">
wsp:Body()
</wssp:MessageParts>
</wssp:Target>


<wssp:Target>
<wssp:DigestAlgorithm URI="http://www.w3.org/2000/09/xmldsig#sha1" />
<wssp:MessageParts
Dialect="http://www.bea.com/wls90/security/policy/wsee#part">
wls:SecurityHeader(Assertion)
</wssp:MessageParts>
</wssp:Target>


</wssp:Integrity>

<!--
<wssp:Confidentiality>

<wssp:KeyWrappingAlgorithm URI="http://www.w3.org/2001/04/xmlenc#rsa-1_5"/>

<wssp:Target>
<wssp:EncryptionAlgorithm
URI="http://www.w3.org/2001/04/xmlenc#tripledes-cbc"/>
<wssp:MessageParts
Dialect="http://www.bea.com/wls90/security/policy/wsee#part">
wls:SecurityHeader(Assertion)
</wssp:MessageParts>
</wssp:Target>

<wssp:Target>
<wssp:EncryptionAlgorithm
URI="http://www.w3.org/2001/04/xmlenc#tripledes-cbc"/>
<wssp:MessageParts
Dialect="http://schemas.xmlsoap.org/2002/12/wsse#part">
wsp:Body()</wssp:MessageParts>
</wssp:Target>

<wssp:KeyInfo />
</wssp:Confidentiality>
-->

<wssp:MessageAge/>

Tuesday, November 3, 2009

WebLogic Server (WLS) to Oracle Service Bus (OSB) to WebLogic Server using SAML Sender Vouches

I'm sure many people were hoping that the next post would be the much anticipated OES-OWSM Custom Assertion, but things have been very busy coming out of Open World. Oddly, I'm working with multiple customers that have been looking for a solution to the following use case:

WLS makes a Web-Services call using JAX-WS to Oracle Service Bus (OSB) passing the identity of the caller using SAML Sender Vouches (SV). OSB serves as an active-intermediary and process the SAML Assertion. OSB then goes and calls a Business Service propagating the user's identity, again using SAML SV.

What makes this use case a little tricky is that OSB at present does not understand WS-Policy 1.2 Assertions, and the JAX-WS stack on WLS does not understand the OSB proprietary assertions. This means that local policy needs to be applied 4 places

  • JAX-WS Client using WS-Policy 1.2
  • OSB Proxy Service using OSB Policy
  • OSB Business Service using OSB Policy
  • WLS Web Services service using WS-Policy 1.2


This post will cover the specific policies and how to apply them at each point.

JAX-WS Client using WS-Policy 1.2



You need to use a ClientPolicyFeature, and load the actual policy from an InputStream. In the example below, I'm running inside a web-application and packaged the policy.xml in the WEB-INF directory.


ClientPolicyFeature cpf =
new ClientPolicyFeature();



InputStreamPolicySource ps = new InputStreamPolicySource(this.getServletContext().getResourceAsStream("/WEB-INF/policy.xml"));

cpf.setEffectivePolicy(ps);


Dispatch dispatch = service.createDispatch(portName,
SOAPMessage.class, Service.Mode.MESSAGE, new WebServiceFeature[] {cpf});




The policy that I'm using is just the standardWssp1.2-2007-Saml1.1-SenderVouches-Wss1.0.xml.


<?xml version="1.0" encoding="windows-1252" ?>
<wsp:Policy wssutil:Id="Wssp1.2-2007-Saml1.1-SenderVouches-Wss1.0.xml" xmlns:wssutil="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy">
<ns1:AsymmetricBinding xmlns:ns1="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
<wsp:Policy>
<ns1:InitiatorToken>
<wsp:Policy>
<ns1:X509Token ns1:IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/AlwaysToRecipient">
<wsp:Policy>
<ns1:WssX509V3Token10 />
</wsp:Policy>
</ns1:X509Token>
</wsp:Policy>
</ns1:InitiatorToken>
<ns1:RecipientToken>
<wsp:Policy>
<ns1:X509Token ns1:IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/Never">

<wsp:Policy>
<ns1:WssX509V3Token10 />
</wsp:Policy>
</ns1:X509Token>
</wsp:Policy>
</ns1:RecipientToken>
<ns1:AlgorithmSuite>
<wsp:Policy>
<ns1:Basic256 />
</wsp:Policy>
</ns1:AlgorithmSuite>
<ns1:Layout>
<wsp:Policy>
<ns1:Lax />
</wsp:Policy>
</ns1:Layout>
<ns1:IncludeTimestamp />

<ns1:ProtectTokens />
<ns1:OnlySignEntireHeadersAndBody />
</wsp:Policy>
</ns1:AsymmetricBinding>
<ns2:SignedSupportingTokens xmlns:ns2="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
<wsp:Policy>
<ns2:SamlToken ns2:IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/AlwaysToRecipient">
<wsp:Policy>
<ns2:WssSamlV11Token10 />
</wsp:Policy>
</ns2:SamlToken>
</wsp:Policy>
</ns2:SignedSupportingTokens>
<ns3:Wss10 xmlns:ns3="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
<wsp:Policy>
<ns3:MustSupportRefKeyIdentifier />
<ns3:MustSupportRefIssuerSerial />

</wsp:Policy>
</ns3:Wss10>
</wsp:Policy>

On the client, beside setting up the policy, you'll also need to configure a SAMLCredentialMapper and a PKICredentialMapper. The PKICredentialMapper needs to have access to a keystore that contains the Private Key used to sign the request.

OSB Proxy Service using OSB Policy


The OSB policy is really just the WLS 9.2 Web Services stack.. Basically, you need to create a WS-Policy and attach it to the request in the proxy service. Also, need to make sure to configure the proxy service to process the WS-Security header.




The actual policy is below.

<?xml version="1.0"?>

<wsp:Policy
xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy"
xmlns:wssp="http://www.bea.com/wls90/security/policy"
xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
xmlns:wls="http://www.bea.com/wls90/security/policy/wsee#part"
wsu:Id="saml-policy"
>

<wssp:Identity>
<wssp:SupportedTokens>
<wssp:SecurityToken TokenType="http://docs.oasis-open.org/wss/2004/01/oasis-2004-01-saml-token-profile-1.0#SAMLAssertionID">
<wssp:Claims>
<wssp:ConfirmationMethod>sender-vouches</wssp:ConfirmationMethod>
</wssp:Claims>
</wssp:SecurityToken>
</wssp:SupportedTokens>
</wssp:Identity>

<wssp:Integrity>

<wssp:SignatureAlgorithm URI="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
<wssp:CanonicalizationAlgorithm
URI="http://www.w3.org/2001/10/xml-exc-c14n#"/>

<wssp:Target>
<wssp:DigestAlgorithm
URI="http://www.w3.org/2000/09/xmldsig#sha1" />
<wssp:MessageParts
Dialect="http://schemas.xmlsoap.org/2002/12/wsse#part">
wsp:Body()
</wssp:MessageParts>
</wssp:Target>

<wssp:Target>
<wssp:DigestAlgorithm URI="http://www.w3.org/2000/09/xmldsig#sha1" />
<wssp:MessageParts
Dialect="http://www.bea.com/wls90/security/policy/wsee#part">
wls:SecurityHeader(Assertion)
</wssp:MessageParts>
</wssp:Target>

</wssp:Integrity>


<wssp:MessageAge/>

</wsp:Policy>



Setting up OSB to consume the SAML Assertion and validate the signature requires the creation of a SAML Identity Asserter. NOTE: In the asserting party configuration, OSB uses a relative path Remember this if you run into trouble getting OSB to understand the assertion.

OSB Business Service using OSB Policy


This was really the only "tricky" part. I had to modify the saml-sv policy to sign the timestamp. The policy on the business service doesn't require it, but it does expect the Timestamp to have a wsu:Id, and making OSB sign it does exactly that. The set-up in OSB is the same as the proxy service, just configure the policy on the request.

The policy on the business service is as follows:


<?xml version="1.0"?>

<wsp:Policy
xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy"
xmlns:wssp="http://www.bea.com/wls90/security/policy"
xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
xmlns:wls="http://www.bea.com/wls90/security/policy/wsee#part"
wsu:Id="saml-policy-to-business-service"
>

<wssp:Identity>
<wssp:SupportedTokens>
<wssp:SecurityToken TokenType="http://docs.oasis-open.org/wss/2004/01/oasis-2004-01-saml-token-profile-1.0#SAMLAssertionID">
<wssp:Claims>
<wssp:ConfirmationMethod>sender-vouches</wssp:ConfirmationMethod>
</wssp:Claims>
</wssp:SecurityToken>
</wssp:SupportedTokens>
</wssp:Identity>

<wssp:Integrity>

<wssp:SignatureAlgorithm URI="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
<wssp:CanonicalizationAlgorithm
URI="http://www.w3.org/2001/10/xml-exc-c14n#"/>

<wssp:Target>
<wssp:DigestAlgorithm
URI="http://www.w3.org/2000/09/xmldsig#sha1" />
<wssp:MessageParts
Dialect="http://schemas.xmlsoap.org/2002/12/wsse#part">
wsp:Body()
</wssp:MessageParts>
</wssp:Target>

<wssp:Target>
<wssp:DigestAlgorithm
URI="http://www.w3.org/2000/09/xmldsig#sha1" />
<wssp:MessageParts
Dialect="http://www.w3.org/TR/1999/REC-xpath-19991116">
wsp:GetHeader(./wsse:Security/wsu:Timestamp)
</wssp:MessageParts>
</wssp:Target>

<wssp:Target>
<wssp:DigestAlgorithm URI="http://www.w3.org/2000/09/xmldsig#sha1" />
<wssp:MessageParts
Dialect="http://www.bea.com/wls90/security/policy/wsee#part">
wls:SecurityHeader(Assertion)
</wssp:MessageParts>
</wssp:Target>

</wssp:Integrity>

<wssp:MessageAge/>

</wsp:Policy>



When adding a business service that requires signing, the proxy service has to have a Service Key Provider. This is really just a wrapper around the policies stored in the PKI Mapper. Basically, you select an alias to use to sign the message going to that business service.



Inside of the realm, in order to be able to configure a Service Key Provider, the PKI CredMapper needs to exist. In addition, the SAML Credential Mapper is required to generate the SAML Assertion.

WLS Web Services service using WS-Policy 1.2


This is pretty straight forward.



@WebService
@Policy(uri = "policy:Wssp1.2-2007-Saml1.1-SenderVouches-Wss1.0.xml")
public class Test {


public String hello(String in) {
System.out.println("=====>"+in);
return "Hello "+in;
}

}



Summary


In setting up a scenario as complicated as this there will undoubtedly be challenges. Use the debug settings inside of WLS, they are your friend. In my set-up I added the following JAVA_OPTIONS to my setDomainEnv.cmd


set JAVA_OPTIONS=%JAVA_OPTIONS% %JAVA_PROPERTIES% -Dwlw.iterativeDev=%iterativeDevFlag% -Dwlw.testConsole=%testConsoleFlag% -Dwlw.logErrorsToConsole=%logErrorsToConsoleFlag%
set JAVA_OPTIONS=%JAVA_OPTIONS% -Dweblogic.wsee.verbose=* -Dcom.sun.xml.ws.transport.http.HttpAdapter.dump=true -Dweblogic.xml.crypto.encrypt.verbose=true -Dweblogic.xml.crypto.dsig.debug=true-Dweblogic.xml.crypto.dsig.verbose=true -Dweblogic.wsee.security.debug=true -Dweblogic.wsee.security.verbose=true
set JAVA_OPTIONS=%JAVA_OPTIONS% -Dweblogic.xml.crypto.wss.debug=true
set JAVA_OPTIONS=%JAVA_OPTIONS% -Dweblogic.xml.crypto.wss.verbose=true
set JAVA_OPTIONS=%JAVA_OPTIONS% -Dweblogic.xml.crypto.keyinfo.debug=true
set JAVA_OPTIONS=%JAVA_OPTIONS% -Dweblogic.xml.crypto.keyinfo.verbose=true
set JAVA_OPTIONS=%JAVA_OPTIONS% -Dweblogic.xml.crypto.dsig.debug=true
set JAVA_OPTIONS=%JAVA_OPTIONS% -Dweblogic.xml.crypto.dsig.verbose=true
set JAVA_OPTIONS=%JAVA_OPTIONS% -Dweblogic.xml.crypto.encrypt.debug=true
set JAVA_OPTIONS=%JAVA_OPTIONS% -Dweblogic.xml.crypto.encrypt.verbose=true
set JAVA_OPTIONS=%JAVA_OPTIONS% -Dweblogic.servlet.DIEnabled=true
set JAVA_OPTIONS=%JAVA_OPTIONS% -Dweblogic.debug.DebugSecuritySAMLService=true
set JAVA_OPTIONS=%JAVA_OPTIONS% -Dweblogic.debug.DebugSecuritySAMLCredMap=true
set JAVA_OPTIONS=%JAVA_OPTIONS% -Dweblogic.debug.DebugSecuritySAMLAtn=true
set JAVA_OPTIONS=%JAVA_OPTIONS% -Dweblogic.debug.DebugSecuritySAMLLib=true
set JAVA_OPTIONS=%JAVA_OPTIONS% -Dweblogic.debug.DebugSecuritySAML2Service=true
set JAVA_OPTIONS=%JAVA_OPTIONS% -Dweblogic.debug.DebugSecuritySAML2CredMap=true
set JAVA_OPTIONS=%JAVA_OPTIONS% -Dweblogic.debug.DebugSecuritySAML2Atn=true
set JAVA_OPTIONS=%JAVA_OPTIONS% -Dweblogic.debug.DebugSecuritySAML2Lib=true
set JAVA_OPTIONS=%JAVA_OPTIONS% -Dweblogic.debug.DebugSecurityCredMap=true


This gives you good visibility into where the issues are. Also can't hurt to have the weblogic.security.atn and weblogic.security.credmap debug categories on. When trying to figure out what is going on, more information is better. Be patient, this will spit out a lot of information, but look through it and you can normally get to the issue.

Thursday, October 15, 2009

What is SOA Security?

This question has come up in a few contexts lately. One interesting example was the recent creation of the soa-security sub category on samplecode.oracle.com . There is no multiple inheritance on the site, so it has to either go into security or soa. This begs the question "Is SOA security anything more than just regular security?" Regular security in this context means web-services security - authentication, authorization, audit etc for web-services. Admittedly, on this blog, we spend a lot of time discussing the mechanics of applying these types of controls to web-services in various products and architectures, but is that all that SOA security is?

Part of the success of this blog has been that its pretty much "manifesto-free", so I'll try to stay focused - the often overlooked area of SOA security is design time governance. Most services are not exposed on the public network. The security for the services at runtime is provided by simply being on the intranet, behind the firewall. We've discussed this before around the use of SAML Bearer confirmation method. The bigger issue is how to ensure that people are selecting the right services to use from the UDDI registry, and only those which they (either the developer of the application) is authorized to use. I think the notion of design time SOA security (often called SOA governance) is nicely discussed here, by Bob Rhubart.

There are some things about services and how they are composed and reused in SOA that need to be managed. How much design time governance (i.e. restrictions) obviously varies from environment to environment. I worked with one customer - that I saw again at OOW a few days ago - who pointed me to the the trustcom project. This is a project being looked at by European government agencies, and "frictionless commerce" with SOA. It is pretty dense stuff, but basically consider the concept of creating a virtual organization to go a perform a business (BPEL) process. A BPEL process has roles, so essentially you want to do is select a service provider for each role and then very easily swap providers in and out if for example, the provider is not meeting their SLAs. So when composing this process, you want to make sure that you're always using the "right" provider. So to do this, you need to look them up in the repository of which contains many, many service providers. So, the UDDI registry or repository needs to restrict access to only the members of the Virtual Organization and their services. There are obviously runtime implications to this model as well, but it does illustrate some of the interesting design time decisions around SOA Security (Governance)

Wednesday, October 7, 2009

Fat Client and SOA - A case for SAML Sender Vouches and STS

The basic scenario is that users need to "log into" their fat client applications, and then go and access some services (let's assume SOAP based) over the internet.

There are a number of questions that drive the solution in a case like this:


  • What directory/data source will users be authenticating to? A local source or a remote source?
  • Are those same directories/data sources readily available to the consuming services?


In the cases where the directory and the services are in the same security domain, and the directory is "readily available", there is no need for something elaborate. I think using the native authentication of the directory (say LDAP) and then passing the users identity to the services as something simple (HTTP Header or WS-Security UsernameToken (no password)) would probably work. Applications can just take the username (or dn) from the request and callback to the directory to get additional information. One last thing, you need to have some mitigation strategy for avoiding people spoofing DNs (adding a DN that isn't there's to the request). The simplest way to is to do the requests over 2-way SSL. Package the certificate with the application and there you go. BTW, the CSF function of OPSS is a nice approach for this user case - relies on Java Security to ensure that only authorized applications can have access to the credential (password for decrypting the private key).

The harder use case is more of a federated model - example, the user needs to authenticate locally, but the services are in another security domain. In this model, if there is additional information that the services need about the user, they need to be passed in some form. I think that SAML-Sender Vouches works nicely here. So, the application authenticates locally and then gets a SAML Assertion, signed by the issuer. The SAML Assertion could/should contain additional information needed by the service - groups/roles/attributes etc. The SAML Assertion is added to the message and the message is signed.

This is actual a good use case for an STS. Basically, the STS is taking username and password in and returning a SAML Assertion for the service. Think of it as a standards based authentication service, where the standard is WS-Trust. The stand-alone application can just be configured to point to the local STS and the application is done - no need to specify support for LDAP, RDBMS...that's left to the local deployment.

The reality is that you could actually solve the first scenario with SAML/STS it may just be overkill, but starting with this architecture does provide much more flexible business models. For example, some customers of the service want to authenticate locally, while others want to authenticate centrally. Not a problem. Its simply a matter of configuration. In the fully federated case, the centralized service trust the local authentication and can avoid the headache of password management. That issue can be pushed out to local directories - at least that's the vision.

Thursday, October 1, 2009

Calling Oracle Service Bus from MSFT WCF Client Using an STS

I hope that this is the first of two posts. In the second post, I want to able to describe how to do this use case with out an STS. As people know from this blog, I think that an STS has a time and a place. When I first did this integration, there was a real reason for having the STS. We were implementing what was essentially the MSFT claims based authorization model. The STS was calling out to an entitlements system than needed to be invoked using native .net authentication. The alternative was to have OSB generate a Kerberos Ticket for a user that it didn't have the password, and call the entitlements service. Let's just say many people consider this against security best practices. Now that I'm faced with doing this again for another customer, I eager to figure out how to do this without the STS. That aside, here's the approach.

Also, I couldn't have done this without Symon Chang, Anand Kothari, Wil Hopkins - very very smart engineers.

Overview


WCF, by default uses windows authentication. Windows authentication is based on Kerberos, so from the WCF perspective, the most logical way of propagating identity would be to use WS-Security Kerberos Token Profile. This is the standard way of conveying a Kerberos Ticket in a SOAP Message. This is supported in WCF OOTB.


The problem is that OSB 10gR3 does not. OSB10gR3 has no support for Kerberos at the message level. OSB does have support for Kerberos as part of the transport level security provided by SPNEGO. As for message level, OSB 10gR3 has support for Usename/Password, X.509 Certificate, and SAML profiles for WS-Security 1.0. SAML provides the best fit for this use case since it allows for the identity in the windows environment to remain native, only relying on SAML when calling services on the OSB.


WCF also supports WS-Security SAML 1.1 Token Profile for WS-Security 1.0, so this seems like a good profile to use to meet the requirements, and therefore focus on. WCF requires a Security Token Service (STS) to generate the SAML Assertion. Microsoft provides a sample, but the sample needs to be modified to generate a SAML Assertion that OSB understands. Also, WCF favors symmetric bindings for WS-Security. This is probably because WS-Security Kerberos Token profile uses the Kerberos Session Id as the key. OSB 10gR3 only supports an asymmetric binding - X.509 certificates are used to sign the message and bind the SAML assertion to it.


On the OSB side, a pipeline needs to be configured to handle the WS-Security policies. The inbound policy is WS-Security SAML 1.1 Token Profile for WS-Security 1.0 and the outbound policy is that the message is signed by the service. This is because MSFT expects that an endpoint that is protected using WS-Security will secure the response as well. To support this OSB configuration, WLS Security realm needs to be configured to consume and validate SAML Assertions as well as configure Public/Private Key pairs and corresponding trust stores for the message signature operations dictated by the WS-Security policies.


The flow is that a WCF client calls the STS. The STS generates a SAML Assertion signed by the STS that contains the name of the user as the Subject. The SAML Assertion uses the sender-vouches confirmation method. The SAML Assertion is added to the WS-Security Header, and the message is signed by invoking service. The message is sent to OSB where the SAML Assertion is verified along with the message signature. Once the message is processed, the return message is signed by the OSB identity. The signature is validated by the WCF client to ensure that the message has not been tampered and was sent by the OSB.

Customizing the STS Sample to Work with OSB


The sample STS provided by Microsoft needs to be modified to work with OSB in this scenario. The sample STS has the following issues:



  • Sample STS needs to be modified to use X509RawCertificate format. OSB does not support SHA1Thumbprint
  • Sample STS needs to be modified to use Sender-Vouches confirmation method instead of Holder of Key.
  • Sample STS needs to be modified to use sign the assertion with the private key of the issuer, not the encrypted key. OSB does not the use of symmetric encrypted keys, only un-encrypted asymmetric keys.
  • Sample STS needs to be modified to include an AuthenticationStatement in the SAML Assertion. This is where OSB looks for the user's identity.
  • Sample STS needs to be modified to add a wsu:Id to the saml:Assertion, otherwise WCF cannot use it as an IssuedToken with an asymmetric binding


These issues can be addressed mainly by modifying the SamlTokenCreator.class

//-----------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
using System;

using System.Collections.Generic;
using System.Collections.ObjectModel;

using System.IdentityModel.Tokens;

using System.ServiceModel;
using System.ServiceModel.Security;
using System.ServiceModel.Security.Tokens;
using System.Text;
using System.Xml;
using System.Security.Cryptography.X509Certificates;
using System.Net.Security;
using System.ServiceModel.Channels;
using System.ServiceModel.Configuration;
using System.ServiceModel.Description;
using System.Configuration;
using System.Security.Principal;
using Common;


namespace Microsoft.ServiceModel.Samples.Federation
{
public sealed class SamlTokenCreator
{
#region CreateSamlToken()
/// <summary>
/// Creates a SAML Token with the input parameters
/// </summary>
/// <param name="stsName">Name of the STS issuing the SAML Token</param>
/// <param name="proofToken">Associated Proof Token</param>
/// <param name="issuerToken">Associated Issuer Token</param>
/// <param name="proofKeyEncryptionToken">Token to encrypt the proof key with</param>
/// <param name="samlConditions">The Saml Conditions to be used in the construction of the SAML Token</param>
/// <param name="samlAttributes">The Saml Attributes to be used in the construction of the SAML Token</param>
/// <returns>A SAML Token</returns>
public static SamlSecurityToken CreateSamlToken(string stsName,
BinarySecretSecurityToken proofToken,
SecurityToken issuerToken,
SecurityToken proofKeyEncryptionToken,
SamlConditions samlConditions,
IEnumerable<SamlAttribute> samlAttributes)
{





// Create a security token reference to the issuer certificate
SecurityKeyIdentifierClause skic = issuerToken.CreateKeyIdentifierClause<X509RawDataKeyIdentifierClause>();
SecurityKeyIdentifier issuerKeyIdentifier = new SecurityKeyIdentifier(skic);

//Get the user
WindowsIdentity wi = ServiceSecurityContext.Current.WindowsIdentity;

// Create a SamlSubject
SamlSubject samlSubject = new SamlSubject(SamlConstants.UserNameNamespace,
SamlConstants.UserName,
wi.Name);
//Set the Confirmation method to Sender-Vouches
samlSubject.ConfirmationMethods.Add(SamlConstants.SenderVouches);

//Create the Authentication Statement
SamlAuthenticationStatement samlAuthStatement = new SamlAuthenticationStatement();
samlAuthStatement.SamlSubject = samlSubject;

// Put the SamlAttributeStatement into a list of SamlStatements
List<SamlStatement> samlSubjectStatements = new List<SamlStatement>();
samlSubjectStatements.Add(samlAuthStatement);

// Create a SigningCredentials instance from the key associated with the issuerToken.
SigningCredentials signingCredentials = new SigningCredentials(issuerToken.SecurityKeys[0],
SecurityAlgorithms.RsaSha1Signature,
SecurityAlgorithms.Sha1Digest,
issuerKeyIdentifier);


// Create the SamlAssertion
String assertionId = "_"+Guid.NewGuid().ToString();

SamlAssertion samlAssertion = new SamlAssertion(assertionId,
"uri:"+stsName.Replace(' ','_'),
DateTime.UtcNow,
samlConditions,
new SamlAdvice(),
samlSubjectStatements
);

//Wrap the SamlAssertion so that the wsu:Id can be added
CustomSamlAssertion customAssertion = new CustomSamlAssertion(samlAssertion);

// Set the SigningCredentials for the SamlAssertion
customAssertion.SigningCredentials = signingCredentials;


// Create a SamlSecurityToken from the SamlAssertion and return it
SamlSecurityToken st = new SamlSecurityToken(customAssertion);

return st;
}

#endregion

private SamlTokenCreator() { }

static X509Certificate2 LookupCertificate(StoreName storeName, StoreLocation storeLocation, string thumbprint)
{
X509Store store = null;
try
{
store = new X509Store(storeName, storeLocation);
store.Open(OpenFlags.ReadOnly);
X509Certificate2Collection certs = store.Certificates.Find(X509FindType.FindByThumbprint,
thumbprint, false);
if (certs.Count != 1)
{
throw new Exception(String.Format("FedUtil: Certificate {0} not found or more than one certificate found", thumbprint));
}
return (X509Certificate2)certs[0];
}
finally
{
if (store != null) store.Close();
}
}

}
}


This code above references another class - CustomSAMLAssertion.class. This class fixes the issue of the SAMLAssertion not having a wsu:Id

using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens;
using System.Text;
using System.Xml;
using System.IO;

namespace Common
{
class CustomSamlAssertion: SamlAssertion
{


public CustomSamlAssertion(SamlAssertion theAssertion):
base(
theAssertion.AssertionId,
theAssertion.Issuer,theAssertion.IssueInstant,
theAssertion.Conditions,
theAssertion.Advice,
theAssertion.Statements)
{


}

public override void WriteXml(System.Xml.XmlDictionaryWriter writer, SamlSerializer samlSerializer, System.IdentityModel.Selectors.SecurityTokenSerializer keyInfoSerializer)
{
StringBuilder myBuilder = new StringBuilder();
XmlDictionaryWriter myWriter = XmlDictionaryWriter.CreateDictionaryWriter(XmlDictionaryWriter.Create(myBuilder));


base.WriteXml(myWriter, samlSerializer, keyInfoSerializer);

myWriter.Close();

String contents = myBuilder.ToString();

//contents = contents + "";


XmlDictionaryReader reader =
XmlDictionaryReader.CreateDictionaryReader(XmlDictionaryReader.Create(new StringReader(contents)));


StringBuilder myBuilder2 = new StringBuilder();
XmlDictionaryWriter myWriter2 = XmlDictionaryWriter.CreateDictionaryWriter(XmlDictionaryWriter.Create(myBuilder2));

try
{
while (reader.Read())
{

WriteShallowNode(reader, writer);


}
}
catch (Exception e)
{
Console.Out.WriteLine(e);
//writer.Flush();
//String contents2 = myBuilder2.ToString();

//throw e;

return;


}

//writer.Flush();

}

void WriteShallowNode(XmlReader reader, XmlWriter writer)
{

if (reader == null)
{

throw new ArgumentNullException("reader");

}

if (writer == null)
{

throw new ArgumentNullException("writer");

}



switch (reader.NodeType)
{

case XmlNodeType.Element:

//writer.WriteStartElement(reader.LocalName);

writer.WriteStartElement(reader.Prefix, reader.LocalName, reader.NamespaceURI);

writer.WriteAttributes(reader, true);

if (reader.LocalName.Equals("Assertion")) {


writer.WriteAttributeString(
"wsu",
"Id",
"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd",
this.AssertionId);
}



if (reader.IsEmptyElement)
{

writer.WriteEndElement();

}

break;

case XmlNodeType.Text:

writer.WriteString(reader.Value);

break;

case XmlNodeType.Whitespace:

case XmlNodeType.SignificantWhitespace:

writer.WriteWhitespace(reader.Value);

break;

case XmlNodeType.CDATA:

writer.WriteCData(reader.Value);

break;

case XmlNodeType.EntityReference:

writer.WriteEntityRef(reader.Name);

break;

case XmlNodeType.XmlDeclaration:

break;


case XmlNodeType.ProcessingInstruction:

writer.WriteProcessingInstruction(reader.Name, reader.Value);

break;

case XmlNodeType.DocumentType:

writer.WriteDocType(reader.Name, reader.GetAttribute("PUBLIC"), reader.GetAttribute("SYSTEM"), reader.Value);

break;

case XmlNodeType.Comment:

writer.WriteComment(reader.Value);

break;

case XmlNodeType.EndElement:

writer.WriteEndElement();

break;

}

}


}
}


Configuring the WCF Client


WCF supports a large number of authentication methods and profile bindings simply and easily. This is typically done by modifying the configuration file through the WCF Service Configuration Editor. Unfortunately, there is no way through configuration to set-up the client. This needs to be done programmatically. The WS-Policy that OSB uses is essentially as follows:

<?xml version="1.0"?>
<wsp:Policy
xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy"
xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702"
>
<sp:AsymmetricBinding>
<wsp:Policy>
<sp:InitiatorToken>
<wsp:Policy>
<sp:X509Token
sp:IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/AlwaysToRecipient">
<wsp:Policy>
<sp:WssX509V3Token10/>
</wsp:Policy>
</sp:X509Token>
</wsp:Policy>
</sp:InitiatorToken>
<sp:RecipientToken>
<wsp:Policy>
<sp:X509Token
sp:IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/Never">
<wsp:Policy>
<sp:WssX509V3Token10/>
</wsp:Policy>
</sp:X509Token>
</wsp:Policy>
</sp:RecipientToken>
<sp:AlgorithmSuite>
<wsp:Policy>
<sp:Basic256/>
</wsp:Policy>
</sp:AlgorithmSuite>
<sp:Layout>
<wsp:Policy>
<sp:Lax/>
</wsp:Policy>
</sp:Layout>
<sp:IncludeTimestamp/>
<sp:ProtectTokens/>
<sp:OnlySignEntireHeadersAndBody/>
</wsp:Policy>
</sp:AsymmetricBinding>
<sp:SignedSupportingTokens>
<wsp:Policy>
<sp:SamlToken
sp:IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/AlwaysToRecipient">
<wsp:Policy>
<sp:WssSamlV11Token10/>
</wsp:Policy>
</sp:SamlToken>
</wsp:Policy>
</sp:SignedSupportingTokens>
<sp:Wss10>
<wsp:Policy>
<sp:MustSupportRefKeyIdentifier/>
<sp:MustSupportRefIssuerSerial/>
</wsp:Policy>
</sp:Wss10>
</wsp:Policy>


The translation between this policy and the WCF APIs is pretty straight forward with one exception - the SAML Token itself. In WCF, the SAML Token is retrieved from the STS, so the WCF client needs to be configured to communicate to it. In WCF, authentication from a token retrieved from an STS is called IssuedToken. All of this can be done programmatically through the WCF APIs. For simplicity sake, the creation of the custom AsymmetricSecurity binding can be encapsulated as a WCF Binding Element Extension. This allows for the inclusion of custom binding elements () inside of a custombinding.


<extensions>
<bindingElementExtensions>
<add name="osbsecurity" type="OSBWCFExtensions.OSBSecurityElement, OSBWCFExtensions, Version=1.0.0.0, Culture=neutral, PublicKeyToken=63fc46aa660659ca" />
</bindingElementExtensions>
</extensions>

<bindings>
<customBinding>
<binding name="HelloWorldServiceServiceSoapBinding">
<textMessageEncoding maxReadPoolSize="64" maxWritePoolSize="16"
messageVersion="Soap12" writeEncoding="utf-8">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
maxBytesPerRead="4096" maxNameTableCharCount="16384" />
</textMessageEncoding>
<osbsecurity STSAddress="http://fedtest/FederationSample/HomeRealmSTS/STS.svc"/>
<httpsTransport manualAddressing="false" maxBufferPoolSize="524288"
maxReceivedMessageSize="165536" allowCookies="false" authenticationScheme="Anonymous"
bypassProxyOnLocal="false" hostNameComparisonMode="WeakWildcard"
keepAliveEnabled="true" maxBufferSize="165536" proxyAuthenticationScheme="Anonymous"
realm="" transferMode="Buffered" unsafeConnectionNtlmAuthentication="false"
useDefaultWebProxy="true" requireClientCertificate="true"/>



</binding>
</customBinding>

Inside of the OSBSecurityElement, the WCF API calls are made that create the proper binding for sending a SAML Assertion to OSB.

protected override System.ServiceModel.Channels.BindingElement CreateBindingElement()
{

//Retrieve the STS Address from the config
ConfigurationProperty stsConfig = this.Properties["STSAddress"];


//Set-up the Asymmetric binding with the recipient and initiator's parameters
//Keys are identified by the issuersSerial as required by the policy
//OSB does not support derived keys, so they are disabled
X509SecurityTokenParameters initiatorParams = new X509SecurityTokenParameters(X509KeyIdentifierClauseType.IssuerSerial, SecurityTokenInclusionMode.AlwaysToRecipient);
initiatorParams.RequireDerivedKeys = false;


X509SecurityTokenParameters recipientParams = new X509SecurityTokenParameters(X509KeyIdentifierClauseType.IssuerSerial, SecurityTokenInclusionMode.Never);
recipientParams.RequireDerivedKeys = false;

AsymmetricSecurityBindingElement security = new AsymmetricSecurityBindingElement(recipientParams, initiatorParams);


security.SecurityHeaderLayout = SecurityHeaderLayout.Lax;
security.MessageSecurityVersion = MessageSecurityVersion.WSSecurity10WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10;
security.SetKeyDerivation(false);

//Configure the STS and the resulting SAML Assertion as a signed supporting token
WSHttpBinding stsBinding = new WSHttpBinding();

//This credential type is how the caller identifies themself to the STS
stsBinding.Security.Message.ClientCredentialType = MessageCredentialType.Windows;

IssuedSecurityTokenParameters issuedTokenParamters =
new IssuedSecurityTokenParameters("", new EndpointAddress((String)base["STSAddress"]), stsBinding);

issuedTokenParamters.RequireDerivedKeys = false;
issuedTokenParamters.ReferenceStyle = SecurityTokenReferenceStyle.Internal;
issuedTokenParamters.InclusionMode = SecurityTokenInclusionMode.AlwaysToRecipient;
security.EndpointSupportingTokenParameters.Signed.Add(issuedTokenParamters);

//Set this to process the signature of the response
security.AllowSerializedSigningTokenOnReply = true;

return security;
}
}

By using the custom binding element extension, the client code remains unchanged:

HelloWorldClient client = new HelloWorldClient();
Console.Out.WriteLine(client.test1("WCF Client"));

Configuring OSB Domain's Security Domian


The inbound SAML processing requires the creation and configuration of a SAML Identity Asserter. For this scenario, the SAML V2 Identity Asserter should be used. It supports SAML 1.1 sender-vouches subject confirmation method. It needs to be configured with an asserting party that corresponds to the STS. Since the SAML Assertion is signed, OSB needs to be configured to trust the signer of the assertion. This can be done my adding the certificate authorities (CAs) that make up the STS's certificate chain to the list of trusted CAs. Which keystore to add them to depends of the trust mode that the OSB domain is running, but by default, these can be added to the cacerts keystore found in JRE_HOME/jre/lib/security.

In some scenarios, the identity being asserted by the SAML assertion can be trusted, and in others, the identity needs to be validated against some other authentication source - mainly Active Directory. OSB domain can be configured to support both. To trust the identity, a SAML Authentication Provider needs to be added to the realm. Make sure to configure it with an appropriate JAAS Control Flag. The simplest way to avoid any conflicts is to mark all of the authentication providers as OPTIONAL. Also, the asserting party configuration in the SAML Identity Asserter needs to be configured to Allow Virtual Users. Otherwise, the SAML Authentication Provider will not work. If "Allow Virtual Users" is not checked for the asserting party, then the security realm will try to validate the user against the authentication providers configured for the realm. The name that the STS above generates is of the form domain/username. In most cases, a custom username mapper will need to be written and configured on the SAML Identity Asserter to split off the domain portion of the name.

A PKI CredMapper needs to be configured so that OSB can generate digital signatures for outbound requests. The PKI CredMapper is configured to point to a Java Keystore. The identity of the OSB should be available in this keystore, and should be the same identity as the ServiceCert configured in the WCF client.

Configuring the OSB Pipeline


The OSB service needs to be configured to process the WS-Security header sent by WCF. The inbound request message needs to be configured with the SAML Token Profile 1.0 - Sender Vouches policy.
<wsp:Policy
xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy"
xmlns:wssp="http://www.bea.com/wls90/security/policy"
xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
xmlns:wls="http://www.bea.com/wls90/security/policy/wsee#part"
wsu:Id="samlPolicy-sender-vouches-simple">
<wssp:Identity>
<wssp:SupportedTokens>
<wssp:SecurityToken TokenType="http://docs.oasis-open.org/wss/2004/01/oasis-2004-01-saml-token-profile-1.0#SAMLAssertionID">
<wssp:Claims>
<wssp:ConfirmationMethod>sender-vouches</wssp:ConfirmationMethod>
</wssp:Claims>
</wssp:SecurityToken>
</wssp:SupportedTokens>
</wssp:Identity>
</wsp:Policy>

The OSB response needs be signed. This can be done by creating a Service Key Provider that points to the identity of the OSB, and then adding the predefined Sign.xml policy to the response operation.

References


The mapping of WCF configuration to WS-Policy and the security capabilities are nicely described

A description of why wsu:Id needs to be added to the SAML Assertion

A good discussion of a variation of this use case

The sample STS from Microsoft, which has extended to integrate with OSB

Wednesday, September 23, 2009

"What is the point of all this?"

A truly great question. I'm here at Oracle HQ presenting to a set of very smart architects, discussing message level security, and this is the question.

"Why go through the trouble of message level security if the service is behind the firewall?"

"The service is just accessed using HTTPS and Basic Authentication. What's wrong with that?"

The topic of message-level security vs. transport level/network level security is interesting (and not new). So here's my two cents:

Simpler is better - if you can get away with SSL or network level security - good for you.

So, this begs the question, what use cases require message level security. This is not an exhaustive list but, a few simple guidelines:

Asynchronous - especially long running transactions - having security in the message makes sense. Things like SSO cookies and SSL sessions will timeout.

Multi Party - transport is typically point to point, so you can encrypt something for one person - but not many parties. WS-Security supports the encryption of parts of the message.

"Truly Loosely Coupled" - In SOA, if you want to be able to send the message to any service, you can't count on what security controls other parties may provide, so if there is confidential information, best to encrypt it in the message.

Federated - When the message is going to change security domains (read: networks), conveying who the user and the calling service can easily be contained in the message using SAML. This use case is extended to include attributes. This use case assumes that in the other network it may be hard/impossible to validate the user's credentials, so trusting the message is the best bet.

So, if you're doing simple REST style services (stateless/synchronous) or RPC style API calls, look at the transport level - its probably sufficient and it is simple. Message level security introduces some additional complexity and effort, but is absolutely required to address many real-world use cases.