Thursday, June 13, 2013

Part 3: Kerberos Authentication, RBAC and SAML identity propagation in OAG

This post is the third one of a series by Andre Correa and Paulo Pereira on OAG (Oracle API Gateway).

In the first post we introduced the use case and talked about the Kerberos authentication part.

In the second post we talked about Role Based Access Control.

In this one we describe how to build a SAML token out of the authenticated user and sign it so it properly interoperates with an OWSM server-side policy applied to OSB proxy service. We also cover the necessary OWSM configuration in OSB and SOA. As a reminder, a typical request in our exercise flows through OTD -> OAG -> OTD -> OSB -> OTD -> SOA -> Stub server, and we're required to keep the user identity all the way up to the Stub server.

Now we're specifically talking about the third policy in our overall circuit:

'Add SAML token policy' is as simple as:

We first add the SAML token (using the Insert SAML Authentication Assertion filter), then we sign it (using the XML Signature Generation filter). Let's look at each filter in detail.

1. Insert SAML Authentication Assertion

Note: We only present the screenshots where we have to change any of the default values or when we have some considerations to make.

1.1. Assertion Details

Caution: Notice the Issuer Name. It has to be a name registered for the OWSM server side policy in OSB. Otherwise, SAML validation will fail.

It's important to realize that the assertion's Subject Name Identifier is going to be whatever is in the attribute. If you've read the second post of this series, in the very first filter we process the Kerberos SPN (<SERVICE>/<USER_ID>@<DOMAIN_NAME>) and store just the <USER_ID> part in that attribute.

We have configured expiration time in 5 mins. And the SAML version is 1.1.

1.2. Subject Confirmation Method

No changes here. We're using Sender Vouches, which means we'll have to sign the message, so that the receiver will properly validate the sender's identity. More on this later on.

2. XML Signature Generation

2.1. Signing Key

The message is signed with a private key aliased as orakey, available in a java key store created with the keytool command (more on this shortly). OWSM, on the OSB side, will verify the signature using the corresponding public key certificate. To complete the verification chain, the CA signing the public key certificate is also needed in OWSM key store.

Once you have the private key in the key store, this is how you get it into the filter.

First, click on the Signing Key button. You get the following.

By clicking the Keystore button, you get:

Click the button on the top right to pick the keystore in the fie system.

Once you pick the jks file, since it is likely password protected, OAG Policy studio asks you for the password. The same for the private key alias.

Right passwords entered, now just pick the private key.

2.2 Key Info

Have in mind that we’re building a WSS policy to interoperate with an OWSM policy that is going to be attached to the OSB proxy service. As such there’s an important “gotcha” when telling OAG how key information about the digital signature is transmitted. In this use case, we’ll attach wss11_saml_token_with_message_integrity_service_policy to OSB. As such, we must instruct OAG to deliver key information within a BinarySecurityToken element.

This is done in the KeyInfo tab under the SigningKey tab in XML Digital Signature filter:


Warning: If you go with the pre-selected “Embed public key information”, you’ll hit a PolicyEnforcementException in OWSM, as the following.

Caused by: oracle.wsm.common.sdk.WSMException: GenericFault : generic error  
 at oracle.wsm.policyengine.impl.runtime.WSPolicyRuntimeExecutor.executeSimpleAssertion( 
 at oracle.wsm.policyengine.impl.runtime.WSPolicyRuntimeExecutor.executeAndAssertion( 
 at oracle.wsm.policyengine.impl.runtime.WSPolicyRuntimeExecutor.execute( 
 at oracle.wsm.policyengine.impl.PolicyExecutionEngine.execute( 
 at oracle.wsm.agent.WSMAgent.processCommon( 
 at oracle.wsm.agent.WSMAgent.processRequest( 
 at oracle.fabric.common.BindingSecurityInterceptor.processRequest( 
 ... 35 more 
Caused by: java.lang.ClassCastException: cannot be 
cast to 
 at oracle.wsm.policyengine.impl.runtime.AssertionExecutor.execute( 
 at oracle.wsm.policyengine.impl.runtime.WSPolicyRuntimeExecutor.executeSimpleAssertion( 
 ... 41 more 
<Mar 18, 2013 6:03:55 AM PDT> <Error> <oracle.webservices.service> 
<OWS-04115> <An error occurred for port: FabricProvider: oracle.fabric.common.PolicyEnforcementException: GenericFault : generic error.> 

And the corresponding SOAP Envelope. Notice the dsig:X509Data element inside dsig:KeyInfo element.

   1: <soap:Envelope xmlns:soap="">
   2: <soap:Header>
   3: <wsse:Security xmlns:wsse=""
   4: <dsig:Signature xmlns:dsig="" Id="Id-0001363611835046-fffffffff235d266-2">
   5: <dsig:SignedInfo>
   6: <dsig:CanonicalizationMethod Algorithm=""/>
   7: <dsig:SignatureMethod Algorithm=""/>
   8: <dsig:Reference URI="#Id-e9007152514710bb4b400000-1">
   9: <dsig:Transforms>
  10: <dsig:Transform Algorithm=""/>
  11: </dsig:Transforms>
  12: <dsig:DigestMethod Algorithm=""/>
  13: <dsig:DigestValue>ndYlZEVrtLWKjC39gbpWvqFSbgg=</dsig:DigestValue>
  14: </dsig:Reference>
  15: <dsig:Reference URI="#Id-0001363611835046-fffffffff235d266-1">
  16: <dsig:Transforms>
  17: <dsig:Transform Algorithm=""/>
  18: </dsig:Transforms>
  19: <dsig:DigestMethod Algorithm=""/>
  20: <dsig:DigestValue>DgPyKqDj6L9unbTaNU4z8ef/hyk=</dsig:DigestValue>
  21: </dsig:Reference>
  22: </dsig:SignedInfo>
  23: <dsig:SignatureValue>akll4kGbg6FoB2CbF3CKLFxdXJh4YkEY1VL+Oymvl33kLRrrTX+RmPEit6ykY4afKqcvu0f6M8etLt2d6maDL6P/+ZdhuNyxA487cOyX9VUtTePYPrSf1NAzGUf58Sr/gTLopthfV7PDE3GSQ8mfiZLHTIaLNNLRRAOs1f84tys=</dsig:SignatureValue>
  24: <dsig:KeyInfo Id="Id-0001363611835046-fffffffff235d266-3">
  25: <dsig:X509Data>
  27: </dsig:X509Data>
  28: </dsig:KeyInfo>
  29: </dsig:Signature>
  30: <saml:Assertion xmlns:saml="urn:oasis:names:tc:SAML:1.0:assertion" AssertionID="Id-e9007152514710bb4b400000-1" IssueInstant="2013-03-18T13:03:55Z" Issuer="" MajorVersion="1" MinorVersion="1">
  31: <saml:Conditions NotBefore="2013-03-18T13:03:54Z" NotOnOrAfter="2013-03-18T13:08:54Z"/>
  32: <saml:AuthenticationStatement AuthenticationMethod="urn:ietf:rfc:1510" AuthenticationInstant="2013-03-18T13:03:55Z">
  33: <saml:Subject>
  34: <saml:NameIdentifier Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified">weblogic</saml:NameIdentifier>
  35: <saml:SubjectConfirmation>
  36: <saml:ConfirmationMethod>urn:oasis:names:tc:SAML:1.0:cm:sender-vouches</saml:ConfirmationMethod>
  37: </saml:SubjectConfirmation>
  38: </saml:Subject>
  39: </saml:AuthenticationStatement>
  40: </saml:Assertion> 
  41: </wsse:Security> 
  42: </soap:Header>
  43: <soap:Body xmlns:wsu="" wsu:Id="Id-0001363611835046-fffffffff235d266-1">
  44: <process xmlns="">
  45: <input>andre</input>
  46: </process>
  47: </soap:Body>
  48: </soap:Envelope>

Tip: You overcome the exception by picking the Security Token Reference option. Here’s the corresponding SOAP Envelope. Notice we now have a wsse:SecurityTokenReference element within the dsig:KeyInfo element.

   1: <soap:Envelope xmlns:soap="">
   2: <soap:Header>
   3: <wsse:Security xmlns:wsse=""
   4: <wsse:BinarySecurityToken xmlns:wsu=""
   5: wsu:Id="Id-0001363612255582-000000007deffb30-1" ValueType=""
   7: <dsig:Signature xmlns:dsig="" Id="Id-0001363612255582-000000007deffb30-3">
   8: <dsig:SignedInfo>
   9: <dsig:CanonicalizationMethod Algorithm=""/>
  10: <dsig:SignatureMethod Algorithm=""/>
  11: <dsig:Reference URI="#Id-0001363612255582-000000007deffb30-2">
  12: <dsig:Transforms>
  13: <dsig:Transform Algorithm=""/>
  14: </dsig:Transforms>
  15: <dsig:DigestMethod Algorithm=""/>
  16: <dsig:DigestValue>d8+JhSgsm5F+GA3WT2d6L8Ae94o=</dsig:DigestValue>
  17: </dsig:Reference>
  18: <dsig:Reference URI="#Id-43116dec5147125f15400000-1">
  19: <dsig:Transforms>
  20: <dsig:Transform Algorithm=""/>
  21: </dsig:Transforms>
  22: <dsig:DigestMethod Algorithm=""/>
  23: <dsig:DigestValue>EruO9RPerewwBO8Af78QLqELjog=</dsig:DigestValue>
  24: </dsig:Reference>
  25: </dsig:SignedInfo>
  26: <dsig:SignatureValue>Od62BfZGKe75Gih9GpQZjwk1r6Gw6Gkd1hwQVEYWPSuwiunwLxAfywYL/wqz0xv8kuSWxILQJlt0IYgUUMV4knr4cCWK71Gu+RZKRRXuoVQ+b3rAqy5+rC9QiRbI2OLpUwdoGVN05dVwGdmt9ZRvEL+Vu+MdOLICR1t27rFuSuE=</dsig:SignatureValue>
  27: <dsig:KeyInfo Id="Id-0001363612255582-000000007deffb30-4">
  28: <wsse:SecurityTokenReference xmlns:wsu="" wsu:Id="Id-0001363612255582-000000007deffb30-5">
  29: <wsse:Reference URI="#Id-0001363612255582-000000007deffb30-1" ValueType=""/>
  30: </wsse:SecurityTokenReference>
  31: </dsig:KeyInfo>
  32: </dsig:Signature>
  33: <saml:Assertion xmlns:saml="urn:oasis:names:tc:SAML:1.0:assertion" AssertionID="Id-43116dec5147125f15400000-1" IssueInstant="2013-03-18T13:10:55Z" Issuer="" MajorVersion="1" MinorVersion="1">
  34: <saml:Conditions NotBefore="2013-03-18T13:10:54Z" NotOnOrAfter="2013-03-18T13:15:54Z"/>
  35: <saml:AuthenticationStatement AuthenticationMethod="urn:ietf:rfc:1510" AuthenticationInstant="2013-03-18T13:10:55Z">
  36: <saml:Subject>
  37: <saml:NameIdentifier Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified">weblogic</saml:NameIdentifier>
  38: <saml:SubjectConfirmation>
  39: <saml:ConfirmationMethod>urn:oasis:names:tc:SAML:1.0:cm:sender-vouches</saml:ConfirmationMethod>
  40: </saml:SubjectConfirmation>
  41: </saml:Subject>
  42: </saml:AuthenticationStatement>
  43: </saml:Assertion> 
  44: </wsse:Security> 
  45: </soap:Header>
  46: <soap:Body xmlns:wsu="" wsu:Id="Id-0001363612255582-000000007deffb30-2">
  47: <process xmlns="">
  48: <input>andre</input>
  49: </process>
  50: </soap:Body>
  51: </soap:Envelope>

2.3. What to Sign

You can pretty much sign anything you want (theoretically). But the message usually has sensitive parts, like the assertion itself or some input element. These are the usual candidates to be signed. Here, we picked the Assertion and the whole Body.


3. Generating the keystore

As we’ve seen, OAG signs the message with its private key stored in a java key store. OWSM will validate the signature using i) OAG’s certificate associated with that private key and ii) the root CA certificate signing OAG’s certificate. In this exercise, we used java keytool to generate a private key and a CSR (Certificate Signing Request) and used OpenSSL as the root CA to issue and sign the certificate.

Depending on your set up, you may have to tweak your openssl.cnf a bit. In OEL, it’s located under /etc/pki/tls.

Or you can just execute the following commands after cd’ing to /etc/pki/CA. Notice that openssl.cnf has some relative references to /etc/pki/CA.

Openssl writes to two files called serial and index.txt (under /etc/pki/CA, by default), to name new certificates and keep track of issued certificates, respectively. Make sure to create them beforehand.

> echo 1000 > serial 
> touch index.txt

a) Using openssl, create a root CA certificate. The command below outputs a signing key (cakey.pem) and a certificate. Preferably, run openssl as root.

> openssl req -new -x509 -extensions v3_ca -keyout private/cakey.pem -out cacert.pem -days 365 -config ../tls/openssl.cnf 

b) Using JDK’s keytool, create a private key for OAG server.

> keytool -genkey -alias orakey -keyalg RSA -keysize 1024 -dname "cn=db,dc=us,dc=oracle,dc=com" -keypass welcome1 -keystore keystore.jks -storepass welcome1

c) Using JDK’s keytool, create a CSR to be sent to your CA created in step a).

> keytool -certreq -v -alias orakey -file db.csr -keypass welcome1 -storepass welcome1 -keystore ./keystore.jks 
Certification request stored in file <db.csr> 
Submit this to your CA

d) Using openssl, issue and sign a certificate for the CSR

> openssl ca –config ../tls/openssl.cnf -in db.csr -out newcerts/db.pem

e) Using JDK’s keytool, import the root CA certificate into the keystore.

> keytool -import -v -trustcacerts -alias rootca -file cacert.pem -keystore keystore.jks -storepass welcome1

f) Using openssl, convert the generated certificate’s format do DER.

> openssl x509 -outform der -in newcerts/db.pem -out newcerts/db.der

g) Import the converted certificate into the keystore.

> keytool -import -v -alias oracert -file newcerts/db.der -keystore keystore.jks -keypass welcome1 -storepass welcome1

At this point ,you should have the following 3 entries in your keystore.jks file:

rootca, Mar 18, 2013, trustedCertEntry, Certificate fingerprint (MD5): 
orakey, Mar 18, 2013, PrivateKeyEntry, Certificate fingerprint (MD5): 
oracert, Mar 18, 2013, trustedCertEntry, Certificate fingerprint (MD5): 

h) As you would not want to give away your private key, create a copy of the keystore, delete the orakey entry from the copy and have it available for OWSM in the OSB domain. OWSM will use oracert and rootca entries to validate the digital signature created by OAG.

At this point, we’re done with all necessary configuration in OAG. Let’s take a look at what needs to be done in OSB and SOA.

4. OWSM configuration in OSB and SOA

4.1 Configure OWSM keystore in OSB and SOA.

You do this either through EM (Enterprise Manager) or wlst. Here we present the EM option. If you have different domains for OSB and SOA (as in our case), perform this step for both.

Navigate to the Security Provider Configuration page, as per:



Click the Configure… button.


In Keystore Path, enter the path to the keystore file you gave to OSB domain in step h) previously.

Note: Key Alias and Crypt Alias have no bearing on validating incoming digital signatures. They are used by OWSM for signing and encrypting outgoing messages. The important thing here is configuring the keystore, which must contain the digital certificates for validating messages signed by OAG.

Note: You need to restart your domain after doing this.

4.2. Attach the OWSM policy to OSB proxy service

OWSM_Policy in OSB

Note: See the policy name. After checking some SAML constraints, it validates message integrity and asserts the user against the configured identity store (unless you use the concept of virtual users, in which case the user in the SAML assertion is implicitly trusted.).

Note: OSB has to be configured/extended with the OWSM Extension, otherwise, OWSM integration won’t be available.

Note: Also make sure the OSB proxy is configured as a SOAP Passive Intermediary (Pass-Through), otherwise it will strip the SAML Assertion off.

4.3. Attach the OWSM policy to the SOA composite

Again, in our flow, OSB calls out SOA through OTD and we need to keep the end user identity all the way through. Hence, we attach the same OWSM policy to the SOA composite.

OWSM_Policy in SOA

Tip: When propagating the identity off the SOA composite, you need to attach a client side SAML policy in your web service references (BPEL partner links). SOA is never a SOAP Passive Intermediary. In other words, you must create a brand new SAML assertion in SOA if you want to preserve the end user identity all the way through in your business process.

All right, this is it for now.

In the fourth post of this series, we’ll cover the client part, how we actually submit requests with a Kerberos token to OAG.

No comments:

Post a Comment

Note: Only a member of this blog may post a comment.