Secure Access to Oracle Identity Manager 11g R2 PS3 REST APIs

REST APIs for Oracle Identity Manager (OIM) 11g R2 PS3 were released recently. The availability of REST APIs enables a variety of newer integrations with the product in addition to already available mechanisms using Java APIs. In this article, we discuss various ways of accessing these REST APIs in a secure manner. Please note that […]

Authenticating to the OIG REST API from an OAM-protected web app

The objective of this post is to describe how a web app protected by an OAM WebGate can authenticate to the OIG REST APIs. In a previous blog post, I provided detailed steps to do the same thing for the SCIM REST APIs; now in this blog post I will explain how the same approach […]

Using Oracle Data Integrator (ODI) to Bulk Load Data into HCM-Cloud

Introduction With its capacity to handle complex transformations and large volumes of data, and its ability to orchestrate operations across heterogeneous systems, ODI is a great tool to prepare and upload bulk data into HCM Cloud. In this post, we are looking at the different steps required to perform this task. Overview of the integration […]

Connecting Oracle Data Integrator (ODI) to the Cloud: Web Services and Security Policies

Introduction When you look at the list of Technologies listed in ODI 12.2.1 Topology, you can see a new entry: SOAP Web Services. Prior to having this Technology defined here, developers connecting to Web Services in ODI had to enter all the connectivity details in their packages when they designed the Web Service call. Now […]

Authenticating to OIM SCIM server using an OAM-generated SAML identity assertion

In a previous post previous post I provided a brief introduction to SCIM. In this post I’m going to dive right in and give an example of using the OIM SCIM services and securing them with OAM. Why would you want to use OIM SCIM services? There are many reasons, however I will focus on […]

Identity Propagation from OAG to REST APIs protected by OWSM

Introduction This post describes the necessary configuration for propagating an end user identity from OAG (Oracle API Gateway) to REST APIs protected by OWSM (Oracle Web Services Manager). The requirements are: 1) Have a Java Subject established in the REST API implementation. 2) Prevent direct access to the REST API, i.e., only OAG should be […]

How to secure Web Services exposed by OAAM Server (oaam_server)

At the end it turned out very simple but I had spent long time in configuring security (authentication and authorization) for Web Services exposed by OAAM 11gR2, thought about writing a blog post on it. For native integration, OAAM Server (oaam_server) exposes Web Services. For the enterprise deployment, security of Web Services would be mandatory.  […]

Part 3: Kerberos Authentication, RBAC and SAML Identity Propagation in OAG

Introduction 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 […]

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.

This is a 3-step process:

a) Create proxy-supporting classes;
b) Use the right client programming model;
c) Attach OWSM policy to the client;

1. Creating proxy-supporting classes

Very straightforward.
Select a project and go to File -> New and select Web Services in the Business Tier category. On the right side, choose Web Service Proxy and follow the wizard.

proxy1

2. Picking the right client programming model

For clients on 11g R1 PS2 and later, use oracle.webservices.WsMetaFactory. If your client is going to run on 11g R1 or 11g R1 PS1, use the deprecated oracle.j2ee.ws.common.jaxws.ServiceDelegateImpl. All these classes are available in jrf-client.jar file, located at oracle_common/modules/oracle.jrf_11.1.1 folder in your middleware home installation.

2.1 Code sample using oracle.j2ee.ws.common.jaxws.ServiceDelegateImpl (up to 11g PS1)

...
import java.net.MalformedURLException;
import java.net.URL;
import javax.xml.namespace.QName;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.ws.BindingProvider;
import oracle.j2ee.ws.common.jaxws.ServiceDelegateImpl;
import oracle.webservices.ClientConstants;
import oracle.wsm.security.util.SecurityConstants;
import org.w3c.dom.Element;
...
String endpoint = "http://127.0.0.1:7101/B7aFusionWebServices-Model-context-root/MyAppModuleService";
URL wsdlURL = new URL(endpoint+"?WSDL");
ServiceDelegateImpl serviceDelegate = new ServiceDelegateImpl(wsdlURL, new QName("http://xmlns.oracle.com/oracle/apps/", "MyAppModuleService"), oracle.webservices.OracleService.class);
MyAppModuleService port = serviceDelegate.getPort(new QName("http://xmlns.oracle.com/oracle/apps/", "MyAppModuleServiceSoapHttpPort"), MyAppModuleService.class );

InputStream isClientPolicy = <Your_Client_Class_Name>.class.getResourceAsStream("client-policy.xml");
Map<String,Object> requestContext = ((BindingProvider) port).getRequestContext();
requestContext.put(ClientConstants.CLIENT_CONFIG, fileToElement(isClientPolicy));
requestContext.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, endpoint);

// Add other properties here. For identity switching add
// requestContext.put(SecurityConstants.ClientConstants.WSS_CSF_KEY, "<AppID_csf_key>");
port.sayHello(name);
...

// Utility method to convert an InputStream into an org.w3c.dom.Element
public static Element fileToElement(InputStream f) throws IOException, Exception {
DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
builderFactory.setValidating(false);
builderFactory.setNamespaceAware(true);
builderFactory.setIgnoringElementContentWhitespace(true);
builderFactory.setIgnoringComments(true);
return builderFactory.newDocumentBuilder().parse(f).getDocumentElement();
}

In this sample, MyAppModuleService is the port interface generated by JDeveloper in the step before.

The parameters to the QName object constructor are the target namespace and the service/port name, both found in the web service wsdl.

2.2 Code sample using oracle.webservices.WsMetaFactory (11g PS2 +)

...
import java.net.URL;
import java.util.Map;
import javax.xml.namespace.QName;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.ws.BindingProvider;
import javax.xml.ws.Service;
import oracle.webservices.ClientConstants;
import oracle.webservices.ImplType;
import oracle.webservices.WsMetaFactory;
import oracle.wsm.security.util.SecurityConstants;
import org.w3c.dom.Element;
...

String endpoint = "http://localhost:7101/WebServiceSample2-WebService-context-root/GreetingPort";
URL serviceWsdl = new URL(endpoint + "?wsdl");
QName serviceQName = new QName("http://sample2.webservice/","GreetingService");
QName portQName = new QName("http://sample2.webservice/","GreetingPort");


Service proxyService = WsMetaFactory.newInstance(ImplType.JRF).createClientFactory().create(serviceWsdl, serviceQName);
Greeting port = proxyService.getPort(portQName, Greeting.class);

InputStream clientPolicyStream = Servlet1.class.getResourceAsStream("client-policy.xml");
Element clientConfigElem = this.fileToElement(clientPolicyStream);

Map<String,Object> requestContext = ((BindingProvider) port).getRequestContext();
requestContext.put(ClientConstants.CLIENT_CONFIG , clientConfigElem);
requestContext.put(SecurityConstants.ClientConstants.WSS_CSF_KEY,"servlet1-key");

port.sayHello();

 

In this sample, Greeting is the port interface generated by JDeveloper in the step before.

The parameters to the QName object constructor are the target namespace and the service/port name, both found in the web service wsdl.

3. Attaching the OWSM policy

The OWSM policy is passed as an org.w3c.dom.Element to the requestContext Map. One way to come up with such Element is through an XML file that contains a reference to the actual OWSM client-side policy to be used.

InputStream clientPolicyStream = Servlet1.class.getResourceAsStream("client-policy.xml");
Element clientConfigElem = this.fileToElement(clientPolicyStream);
Map<String,Object> requestContext = ((BindingProvider) port).getRequestContext();
requestContext.put(ClientConstants.CLIENT_CONFIG , clientConfigElem);
Here are the XML file (client-policy.xml) contents. You have to create a file like this and make it available to your application CLASSPATH. It references the OWSM policy to be given to the requestContext Map.
<?xml version="1.0" encoding="UTF-8"?>
<oracle-webservice-clients>
<webservice-client>
<port-info>
<policy-references>
<policy-reference uri="oracle/wss11_saml_token_client_policy" category="security"/>
</policy-references>
</port-info>
</webservice-client>
</oracle-webservice-clients>

 

For SAML-based identity propagation, use any of the SAML client policies.

In this case, the policy retrieves the user name Principal from the Java Subject who is running the client and adds it to a generated SAML token in the SOAP call header.

3.1. Switching Identities

To propagate a new identity rather than the one executing the client, use a username token-based policy. By the way, the sample using oracle.webservices.WsMetaFactory may use oracle/wss_username_token_client_policy as the policy name in order to propagate the identity referred by the servlet1-key csf key.

Map<String,Object> requestContext = ((BindingProvider) port).getRequestContext(); 
requestContext.put(SecurityConstants.ClientConstants.WSS_CSF_KEY, "servlet1-key");

 

“servlet1-key” must match a key entry in the domain-level credential store that holds the username/password pair required for the use case implementation. Here’s how you create a key for OWSM usage in the credential store using wlst:

wls:/offline> connect()
Please enter your username :weblogic
Please enter your password :
Please enter your server URL [t3://localhost:7001] :t3://localhost:7101
Connecting to t3://localhost:7101 with userid weblogic
...
Successfully connected to Admin Server 'DefaultServer' that belongs to
domain 'DefaultDomain'.
Warning: An insecure protocol was used to connect to the
server. To ensure
on-the-wire security, the SSL port or
Admin port should be used instead.
wls:/DefaultDomain/serverConfig>
createCred(map="oracle.wsm.security",key="servlet1-key",user="weblogic",password="welcome1")

 

In this case, the policy retrieves the username/password pair from the credential store and adds it to a generated username token in the outgoing SOAP header.

What if the client is a Java SE application?

So far so good, but what happens when the client runs on a Java SE environment?

a) How do you get a hold of the OWSM policy?

Add oracle_common/modules/oracle.wsm.policies_11.1.1/wsm-seed-policies.jar, available in your middleware home installation, to the client CLASSPATH. All policy files are in it.

b) How to deal with the credential store (for identity switching) ?

You need to supply the client with 2 files:

1 – cwallet.sso, which is a file-based credential store. In order to author cwallet.sso, I recommend that you use wlst’s createCred command. Yes, you’ll need a JRF-enabled Weblogic server to create it.

2 – jps-config.xml, through -Doracle.security.jps.config Java option. In jps-config.xml, make sure there’s a credential store service instance available for the default context pointing to the folder where cwallet.sso is located, as shown in this sample jps-config.xml:

<?xml version = '1.0' encoding = 'UTF-8'?>
<jpsConfig xmlns="http://xmlns.oracle.com/oracleas/schema/11/jps-config-11_1.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.oracle.com/oracleas/schema/11/jps-config-11_1.xsd">
<property value="doasprivileged" name="oracle.security.jps.jaas.mode"/>
<propertySets/>
<serviceProviders>
<serviceProvider class="oracle.security.jps.internal.credstore.ssp.SspCredentialStoreProvider" name="credstore.provider" type="CREDENTIAL_STORE">
<description>Credential Store Service Provider</description>
</serviceProvider>
<serviceProvider class="oracle.security.jps.internal.idstore.xml.XmlIdentityStoreProvider" name="idstore.xml.provider" type="IDENTITY_STORE">
<description>XML-based IdStore Provider</description>
</serviceProvider>
<serviceProvider class="oracle.security.jps.internal.policystore.xml.XmlPolicyStoreProvider" name="policystore.xml.provider" type="POLICY_STORE">
<description>XML-based PolicyStore Provider</description>
</serviceProvider>
<serviceProvider class="oracle.security.jps.internal.login.jaas.JaasLoginServiceProvider" name="jaas.login.provider" type="LOGIN">
<description>Login Module Service Provider</description>
</serviceProvider>
<serviceProvider class="oracle.security.jps.internal.keystore.KeyStoreProvider" name="keystore.provider" type="KEY_STORE">
<description>PKI Based Keystore Provider</description>
<property value="owsm" name="provider.property.name"/>
</serviceProvider>
</serviceProviders>
<serviceInstances>
<serviceInstance provider="credstore.provider" name="credstore">
<property value="./" name="location"/>
</serviceInstance>
<serviceInstance provider="idstore.xml.provider" name="idstore.xml">
<property value="./jazn-data.xml" name="location"/>
<property value="jazn.com" name="subscriber.name"/>
</serviceInstance>
<serviceInstance provider="policystore.xml.provider" name="policystore.xml">
<property value="./jazn-data.xml" name="location"/>
</serviceInstance>
<serviceInstance provider="jaas.login.provider" name="idstore.loginmodule">
<property value="oracle.security.jps.internal.jaas.module.idstore.IdStoreLoginModule" name="loginModuleClassName"/>
<property value="REQUIRED" name="jaas.login.controlFlag"/>
<property value="true" name="debug"/>
<property value="true" name="addAllRoles"/>
<property value="false" name="remove.anonymous.role"/>
</serviceInstance>
<serviceInstance location="./default-keystore.jks" provider="keystore.provider" name="keystore">
<description>Default JPS Keystore Service</description>
<property value="JKS" name="keystore.type"/>
<property value="oracle.wsm.security" name="keystore.csf.map"/>
<property value="keystore-csf-key" name="keystore.pass.csf.key"/>
<property value="sign-csf-key" name="keystore.sig.csf.key"/>
<property value="enc-csf-key" name="keystore.enc.csf.key"/>
</serviceInstance>
</serviceInstances>
<jpsContexts default="default">
<jpsContext name="default">
<serviceInstanceRef ref="credstore"/>
<serviceInstanceRef ref="idstore.xml"/>
<serviceInstanceRef ref="policystore.xml"/>
<serviceInstanceRef ref="idstore.loginmodule"/>
<serviceInstanceRef ref="keystore"/>
</jpsContext>
</jpsContexts>
</jpsConfig>

Hope this helps some of you dear readers out there.

Weblogic WS-Trust Client and OWSM interoperability

First, I’d like to take the opportunity to wish you all our readers a great 2012, with plenty of health, joy, care for each other and peace! We really appreciate your interest in our posts and hope to be truly contributing to your daily work. With that said…

Did you guys know Weblogic implements a WS-Trust client?  Did you also know that WS-Trust client can interoperate with web services protected by OWSM policies requiring message protection (signing and encryption) ? Those were very helpful to me in satisfying some important requirements for a customer in a recent proof of concept exercise.

This is a long post. It describes a bunch of things that are more or less available across several official books, but also adds some details that are not easily found, especially if you’re interested in troubleshooting.

The customer adopts OSTS (Oracle Secure Token Service) and wanted an alternative to OWSM (Oracle Web Services Manager) client. OSTS is part of Oracle IAM Suite 11.1.1.5, delivered as an OAM (Oracle Access Manager) add-on. For an introduction to OSTS, check this post.

OSTS leverages OWSM policies to protect its WS-Trust endpoints. OWSM 11.1.1.5 also delivers WS-Trust client policies. When your web services clients can leverage the OWSM WS-Trust client policies, great, it just works. In situations where they can’t, alternate solutions need to be thought. This particular customer had a considerable amount of clients running in Weblogic server 10.3.3, where WS-Trust support is not available in the OWSM runtime. We could have looked at web services frameworks like Apache’s AXIS2 or CXF, but Weblogic’s WS-Trust client was just there, waiting to rescue. As you can see if you follow this post, it saved us quite some coding.

I must say that the approach describe here is by no means a recommended architecture for everyone. Every customer scenario is different and should be thought in light of current and future requirements. I must also say that OWSM is the strategic direction and, as such, should always be the preferred approach.

This is basically what I’ve helped the customer to achieve:

scenario

Here are the interaction details:

1) The client makes an RST (Request Secure Token) using Weblogic’s WS-Trust client to the OSTS requesting for a SAML token to be sent to the ws provider. The client identifies itself to the OSTS with username token credentials in the WSS header, but requests a token on behalf of someone else. In this example, on behalf of the client application executing user.

2) OSTS’ OWSM agent validates the WSS part of the request. It needs to decrypt the message and validate the digital signature added by Weblogic’s WS-Trust client. This is where most of interoperability problems arise. The policy attached to OSTS endpoint is oracle/wss11_username_token_with_message_protection_service_policy

3) After doing some extra validation on the RST and the requestor credentials, the OSTS issues the SAML token (RSTR – Request Secure Token Response).

4) The client calls the ws provider passing the issued SAML token along. SAML confirmation method in this case is Sender-Vouches, which means the ws client signs the SAML token. The policy attached to ws provider is oracle/wss11_saml_token_with_message_protection_service_policy.

5) The ws provider sends the response.

Implementation Details

1) Web Service Proxy

Web service JAX-WS proxy is generated for the web service provider as usual. This is done by Weblogic’s clientgen tool via an ANT build script, as shown below:

<project name="ws-client" default="build">
 <property name="wls.hostname" value="localhost"/>

<property name=“wls.port” value=“9003”/>
<property name=“classes-dir” value=“classes”/>
<property name=“src-dir” value=“src”/>
<path id=“client.class.path”>
<pathelement path=“classes”/>
<fileset dir=“${mw.home}/wlserver_10.3/server/lib”>
<include name=“weblogic.jar”/>
<include name=“wseeclient.jar”/>
</fileset>
<pathelement path=“${java.class.path}”/>
</path>
<taskdef name=“clientgen” classpathref=“client.class.path” classname=“weblogic.wsee.tools.anttasks.ClientGenTask” />
<target name=“build”>
<clientgen wsdl=“http://${wls.hostname}:${wls.port}/webservices/GreetingPort?WSDL”
destDir=“${src-dir}”
packageName=“ws.client”
type=“JAXWS”/>
<javac srcdir=“${src-dir}” destdir=“${classes-dir}” includes=“**/*.java”/>
</target>
</project>

Notice that you need weblogic.jar and wseeclient.jar in the CLASSPATH to run clientgen. These files are located under $MW_HOME/wlserver_10.3/server/lib folder.

You don’t generate proxies for the OSTS endpoint. This is implicitly taken care by WLS WS-Trust client.

2) Client Code

My client is a simple servlet, that actually hides some serious heavy-lifting performed by Weblogic’s WS-Trust client. The code is commented so it explains itself. Look at how simple it is.

You get an instance of the proxy port as you would normally do and add a couple of properties to the BindingProvider object in order to make the WS-Trust client invoke OSTS (lines 35-45).

1: package trunk.interop.ws;

2: 
3: import java.io.IOException;
4: import java.io.PrintWriter;
5: import javax.servlet.*;
6: import javax.servlet.http.*;
7: import javax.xml.ws.BindingProvider;
8: import java.util.Map;
9: import weblogic.wsee.message.WlMessageContext;
10: import weblogic.wsee.jaxrpc.WLStub;
11: import weblogic.wsee.security.WSEESecurityConstants;
12: import javax.xml.soap.SOAPConstants;
13: import ws.client.Greeting;
14: import ws.client.GreetingService;
15:
16: public class TrustClientServlet extends HttpServlet {
17:
18: private static final String CONTENT_TYPE = “text/html; charset=windows-1252”;
19: private static final String TRUST_VERSION = “http://docs.oasis-open.org/ws-sx/ws-trust/200512”;
20: private static final String STS_URL = “http://dogwood.us.oracle.com:14100/sts/wss11user”;
21: private static final String STS_POLICY = “StsWss11UntPolicy.xml”;
22: public void init(ServletConfig config) throws ServletException {
23: super.init(config);
24: }
25: public void doGet(HttpServletRequest request, HttpServletResponse response)
26: throws ServletException, IOException {
27:
28: response.setContentType(CONTENT_TYPE);
29: PrintWriter out = response.getWriter();
30: out.println(“<html>”);
31: out.println(“<head><title>TrustClientServlet</title></head>”);
32: out.println(“<body>”);
33: GreetingService service = new GreetingService();
34: Greeting port = service.getGreetingPort();
35: Map<String, Object> requestContext = ((BindingProvider) port).getRequestContext();
36: // Oracle STS endpoint URL
37: requestContext.put(WLStub.WST_STS_ENDPOINT_ON_SAML, STS_URL);
38: // WS-Policy to talk to Oracle STS
39: requestContext.put(WlMessageContext.WST_BOOT_STRAP_POLICY, this.getClass().getResourceAsStream(STS_POLICY));
40: // WS-Trust version
41: requestContext.put(WSEESecurityConstants.TRUST_VERSION, TRUST_VERSION);
42: // SOAP version
43: requestContext.put(WSEESecurityConstants.TRUST_SOAP_VERSION, SOAPConstants.URI_NS_SOAP_1_2_ENVELOPE);
44: // username for whom a token will be requested
45: requestContext.put(WSEESecurityConstants.ON_BEHALF_OF_USER, request.getRemoteUser());
46: out.println(port.sayHello(request.getRemoteUser()));
47: out.println(“</body></html>”);
48: out.close();
49: }
50: }

 

 

3) OWSM Policy in the OSTS endpoint

Line 20 defined the OSTS endpoint. If you append ?WSDL to it and paste it in a browser URL, you can see the WS-Policy generated by the OWSM policy (wss11_username_token_with_message_protection_service_policy) that protects it. It can give you very good insights in case you run into interoperability issues.

In my experience, the interoperability problems are mostly due to mismatch between security bindings, encryption method mechanisms and encryption algorithms.

Here are some typical error messages. I now know how to make them happen anytime. 🙂

a) Due to security binding mismatch:

Caused by: 
oracle.wsm.security.policy.scenario.policycompliance.PolicyComplianceException:
WSM-00059 : Signature method algorithms are mismatched. Expected : http://www.w3.org/2000/09/xmldsig#hmac-sha1,
Actual : http://www.w3.org/2000/09/xmldsig#rsa-sha1.

In this case, make sure both policies use the same security binding. For instance, OWSM’s wss11_username_token_with_message_protection_service_policy is Symmetric. The security binding is NOT configurable in the OWSM policy.

<sp:SymmetricBinding xmlns:sp=“http://schemas.xmlsoap.org/ws/2005/07/securitypolicy”>

  <wsp:Policy>
...
</sp:SymmetricBinding>



b) Due to encryption reference mechanism mismatch:

[2011-09-21T16:04:27.900-07:00] [ms1] [ERROR] [WSM-00034]

[oracle.wsm.resources.security] [tid: [ACTIVE].ExecuteThread: '0' for queue: 
'weblogic.kernel.Default (self-tuning)'] [userId: <anonymous>] [ecid:
5f5492695bd28c21:-83db949:1328e2f9215:-8000-000000000000002c,0]
[WSM_POLICY_NAME:
oracle/wss11_saml_token_with_message_protection_service_policy] [APP:
InteropWebServices] Error in Encryption reference mechanism compliance :
Expected : thumbprint , Actual : ski. Ensure that a compatible policy is
attached at the client side.

This is configurable in the OWSM policy, by changing the orasp:enc-key-ref-mech property value.

<orasp:wss11-username-with-certificates orawsp:name=“WS-Security 1.1 username

with certificates" orawsp:Silent="false" orawsp:Enforced="true" 
orawsp:category="security/authentication, security/msg-protection">

<orasp:username-token orasp:password-type="plaintext"
orasp:add-nonce="false" orasp:add-created="false"/>

<orasp:x509-token orasp:enc-key-ref-mech="ski"/>

<orasp:msg-security orasp:confirm-signature="true"
orasp:sign-then-encrypt="true" orasp:include-timestamp="true"
orasp:encrypt-signature="false" orasp:algorithm-suite="Basic256">

c) Due to encryption algorithms mismatch:

Caused by:

oracle.wsm.security.policy.scenario.policycompliance.PolicyComplianceException: 
WSM-00030 : The encryption method key wrap algorithms do not match : Expected
: http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p,
Actual : http://www.w3.org/2001/04/xmlenc#rsa-1_5.

This is also configurable in the OWSM policy. In the policy snippet above, you can play with the property value of orasp:algorithm-suite and try the Algorithm Suite values as specified in the WS-SecurityPolicy specification. Make sure it matches the one in the client-side policy.

Note: In OSTS, the OWSM policies are available at $MW_HOME/Oracle_IAM1/oam/server/policy/sts-policies.jar.

4) Client-side WS-Policy for OSTS endpoint

Weblogic web service client APIs are smart enough to infer the necessary client configuration from the advertised WS-Policy in the web service WSDL. That said, we’re NOT supposed to attach any client-side policies to talk to our web service provider endpoint. However, this does NOT apply when talking to an STS using the WS-Trust client.

Notice that my client code adds StsWss11UntPolicy.xml to the BindingProvider on line 39. The xml file actually defines the WS-Policy that interoperates with OSTS endpoint protected by OWSM (once I worked through the problems showed above). Here it is:

<?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:SymmetricBinding>
<wsp:Policy>
<sp:ProtectionToken>
<wsp:Policy>
<sp:X509Token
sp:IncludeToken=“http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/Never”>
<wsp:Policy>
<sp:RequireKeyIdentifierReference/>
<sp:WssX509V3Token11/>
</wsp:Policy>
</sp:X509Token>
</wsp:Policy>
</sp:ProtectionToken>
<sp:AlgorithmSuite>
<wsp:Policy>
<sp:Basic256Rsa15/>
</wsp:Policy>
</sp:AlgorithmSuite>
<sp:Layout>
<wsp:Policy>
<sp:Lax/>
</wsp:Policy>
</sp:Layout>
<sp:IncludeTimestamp/>
<sp:OnlySignEntireHeadersAndBody/>
</wsp:Policy>
</sp:SymmetricBinding>
<sp:SignedEncryptedSupportingTokens>
<wsp:Policy>
<sp:UsernameToken
sp:IncludeToken=“http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/AlwaysToRecipient”>
<wsp:Policy>
<sp:WssUsernameToken10/>
</wsp:Policy>
</sp:UsernameToken>
</wsp:Policy>
</sp:SignedEncryptedSupportingTokens>
<sp:Wss11>
<wsp:Policy>
<sp:MustSupportRefKeyIdentifier/>
<sp:MustSupportRefIssuerSerial/>
<sp:MustSupportRefThumbprint/>
<sp:MustSupportRefEncryptedKey/>
<sp:RequireSignatureConfirmation/>
</wsp:Policy>
</sp:Wss11>
<sp:SignedParts>
<sp:Header Namespace=“http://schemas.xmlsoap.org/ws/2004/08/addressing”/>
<sp:Header Namespace=“http://www.w3.org/2005/08/addressing”/>
<sp:Body/>
</sp:SignedParts>
<sp:EncryptedParts>
<sp:Body/>
</sp:EncryptedParts>
</wsp:Policy>



5) Required Configuration in Weblogic server

I’ve been always curious on how to define credential mappings in Weblogic to be used in the context of web services. Time has come. It turns out the system properties in the Troubleshooting section (next) came up very handy to let me know the mappings to be defined.

A credential mapping essentially maps a principal to a credential to be used when talking to external systems. This is very prevalent when the external systems are based on a JCA adapter. But it  applies to web services as well. For example, given authenticated user “andre” (known as the initiator) wants to call web service http://server:7003/webservices/GreetingPort from within a web service client running in Weblogic server, a credential mapping would tell which credentials the user would have to communicate with the web service.

A web service client running in Weblogic is “aware” of the security services provided by the server. In this case, given the WSS requirements stated by our 2 web services (OSTS and ws provider), two types of credential mappings are required in Weblogic:

A) 1 Default Credential Mapping:

Maps an initiator to a username/password pair. Required to add a username token to the outgoing SOAP request when calling the OSTS endpoint. A Default Credential Mapper is OOTB available in Weblogic. We DON’T need a mapping to talk to web service provider endpoint because that one requires a SAML token, which is going to be retrieved from OSTS.

Here’s the credential mapping (Security Realms –> myrealm –> Credential Mappings –> Default > New):

DefaultCredentialMapping

Protocol + Remote Host + Remote Port + Path makes up the web service URL being called. You don’t need to specify any value for Method. Notice that Path value must start with a /.

DefaultCredentialMapping_2

Local User is the initiator, on whose behalf the username under Remote User field is going to be retrieved. Obviously, the Remote User needs to be properly authorized in the remote system (OSTS).

B) 4 PKI Credential Mappings:

A PKI Credential Mapping maps an initiator to either a private key or a certificate. Required to perform digital signature and message encryption when calling the OSTS endpoint and web service provider endpoint. Remember, both endpoints require message protection. A PKI Credential Mapper is NOT OOTB available in Weblogic. To add one, got to Security Realms –> myrealm –> Providers –> Credential Mapping –> New (pick PKICredentialMapper). Make sure to fill in the form in the Provider Specific tab.

PKICredentialMapper

The keystore file Name is relative to the location where you start the Admin server. In my case, I’ve simply put clientkeystore.jks in $MW_HOME/user_projects/domains/<my-domain-name> folder.

Once you add it, restart the Admin Server so you can add the mappings (Security Realm –> myrealm –> Credential Mappings –> PKI –> New). Here are my 4 mappings:

PKICredentialMapping

Notice there are 2 mappings for each endpoint. One to retrieve the private key used for signing and one to retrieve the certificate used for encryption. When defining these mappings, you have the opportunity to inform the alias names in the keystore (clientkeystore.jks) holding the private key and the certificate.

6) Troubleshooting

When running into trouble, these 4 system properties will come to your rescue in the client side. Add them to EXTRA_JAVA_PROPERTIES in setDomainEnv.sh:

  • weblogic.xml.crypto.dsig.verbose=true
  • weblogic.xml.crypto.encrypt.verbose=true
  • weblogic.xml.crypto.keyinfo.verbose=true
  • weblogic.xml.crypto.wss.verbose=true

You should be able to detect, for example, why you’re not able to get a X509 token.

####<Oct 10, 2011 2:55:58 PM PDT> <Debug> <SecurityCredMap> 
<dogwood.us.oracle.com> <ms1> <[ACTIVE] ExecuteThread: '3' for
queue: 'weblogic.kernel.Default (self-tuning)'> <<WLS Kernel>>
<> <aaa1e3e54fdb4a71:63733030:132ef6e25bc:-8000-000000000000008f>
<1318283758414> <BEA-000000> <getCredentials: requestor=Subject:
1
Principal =
weblogic.security.principal.WLSKernelIdentity("<WLS Kernel>")
,
resource=type=<remote>, protocol=http, remoteHost=localhost,
remotePort=9003, path=/webservices/GreetingPort, initiator=Subject:
1
Principal =
weblogic.security.principal.WLSUserImpl("andre")
,
credType=weblogic.pki.TrustedCertificate>
####<Oct 10, 2011 2:55:58 PM PDT> <Info> <>
<dogwood.us.oracle.com> <ms1> <[ACTIVE] ExecuteThread: '3' for
queue: 'weblogic.kernel.Default (self-tuning)'>
<andre> <>
<aaa1e3e54fdb4a71:63733030:132ef6e25bc:-8000-000000000000008f>
<1318283758417> <BEA-000000> <Did not get token for token type http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3
and purpose encrypt from token
handlerweblogic.xml.crypto.wss11.internal.bst.BSTHandler@9527ee>

Thanks to those properties, the log message above tells it was not possible to get a X509 token for user andre to encrypt the message. Then adding a PKI Credential Mapping with the server certificate solves the problem.

And to troubleshoot OWSM, configure TRACE:32 logging level for oracle.wsm in $MW_HOME/user_projects/domains/<domain-name>/config/fmwconfig/servers/<server-name>/logging.xml:

<logger name=‘oracle.wsm’ level=‘TRACE:32’ useParentHandlers=‘false’>

<handler name=‘owsm-message-handler’/>
</logger>

Log messages are sent, by default, to $MW_HOME/user_projects/domains/<domain-name>/servers/<server-name>/logs/owsm/msglogging/diagnostic.log.

Happy 2012!!

Virtual Users in OIF, Weblogic and OWSM

One of the main strengths of SAML is the ability to communicate identity information across security domains that do not necessarily share the same user base. In other words, the authenticated user in one security domain does not necessarily exist in the target security domain providing the service.

Such concept is supported in all major Oracle products that consume SAML tokens: OIF, Weblogic Server and OWSM. The sole purpose of this post is to show how to configure it in these products. Setting up SAML services as a whole involves more than what’s showed here and I recommend the official product documentation for detailed steps.

I hope this can be helpful to someone out there.

OIF (Oracle Identity Federation)

OIF enables federated single sign on for users behind a web browser.

It calls the aforementioned concept “Transient Federation” and enables it via a checkbox (that should be unchecked) in Enterprise Manager OIF’s Console. Notice it also supports the concept of a “Mapped Federation”, where the incoming identity is mapped to some generic user in the local identity store. But here I am talking about the case where there’s no mapping. The user in the SAML assertion is simply trusted.

In order to enable a Transient Federation in OIF, simply make sure “Map Assertion to User Account” checkbox is unchecked in the Service Provider Common tab.

oif

Weblogic Server

Weblogic server provides SAML services that can be leveraged by Web SSO as well web services.
Weblogic calls the concept Virtual Users and implements it in its SAML2IdentityAsserter along with the SAMLAuthenticator.

First, you need to enable your server as a SAML Service Provider. Notice this is done at the server level. Go to Environment –> servers –> <Pick server from list> to get into the screen below:

SAMLServiceProvider

Then add a SAML2IdentityAsserter to the authentication providers list and add an Identity Provider (who does not need to be another Weblogic server) Partner to SAML2IdentityAsserter. Notice that you can add either a Web SSO partner provider or a Web service partner provider. In the case of Web SSO, Weblogic Console will ask you for the partner metadata file.

wls_IdpPartner

In SAML2IdentityAsserter’s Management tab, click the Identity Provider partner link just created and check the “Virtual User” check box:

wls

You also need to add a SAMLAuthenticator provider after the SAML2IdentityAsserter and set its control flag to SUFFICIENT. Also make sure to set the control flag of subsequent authentication providers to SUFFICIENT.

wls_providers

End result is that the SAMLAuthenticator will instantiate a Java Subject populated with a user principal (weblogic.security.principal.WLSUserImpl) from the SAML Subject asserted by SAML2IdentityProvider.

OWSM (Oracle Web Services Manager)

OWSM protects SOAP web services via agents connected to web services providers as well as web services clients. The agent behavior is determined by the policies that get attached to the provider and the client. A client policy typically adds a token to the outgoing SOAP message while the server policy processes it, usually by authenticating and/or authorizing the user (in the case of a security policy).

First of all, a SAML-based security policy needs to be attached to the web service provider. The policy will at some point try to authenticate the subject in the incoming SAML assertion.

OWSM delegates authentication to OPSS (Oracle Platform Security Services). When asserting the SAML Subject to the container, OWSM leverages the SAML Login Module, defined in jps-config.xml and configured via EM (Enterprise Manager).

In other to enable virtual users in this scenario, set the property oracle.security.jps.assert.saml.identity to true for the SAML (or SAML2) Login Module. In EM, click the Weblogic Domain drop-down menu, pick Security –> Security Provider Configuration, click the login module row and then the Edit button. Scroll down to the bottom of the page and the add the property mentioned above to the list of Custom Properties.

opss_samlloginmodule

In order to propagate the change, restart the Admin server as well as the managed server running the web service.

Once this is done, whether or nor the SAML Subject exists in the identity store used by OPSS is irrelevant. It is going to be asserted and a Java Subject containing a user principal is going to be instantiated in the container.

Working with OWSM Policies – Part 1 of some

In this post I discuss the available options to work with OWSM (Oracle Web Services Manager) policies in JDeveloper and Enterprise Manager. OWSM is a component available along with the Oracle SOA Suite and provides policy enforcement point (PEP) agents for SOAP-based messages.

Typically, a service policy is attached to a service endpoint to enforce some pre-defined rules (like enforcing a SAML token, Kerberos token, message confidentiality, SSL, etc). And a corresponding client policy is attached to the client in order to transform the outgoing SOAP message, making it suitable to be enforced in the server side.

OWSM Policies in JDeveloper

OWSM supports two types of repositories for its policy files: file system or database.
When working with JDeveloper, you can choose which one you want to use.
By default, JDeveloper reads policies from the file system. To check that out, go to Tools –> Preferences –>WS Policy Store (on left).

image

The File Store Default Location refers to DefaultDomain oracle/store/gmds directory under $JDEV_USER_DIR’s systemxx.x.x.x.xx.xx.xx folder. Policies are under owsm/policies and assertions are under owsm/assertiontemplates.

The App Server Connection option actually refers to a running Weblogic instance that ultimately gets the policies from a database.

Development groups working with custom policies may like the idea of having policies defined in a central location so that everyone can be sure to work against the very same version of policies. The drawback is that you’ll need that server up and running all the time.

When working with SOA and web services, JDeveloper exposes OWSM policies graphically so they can be picked up with a single click. A description of what the policy does is also shown. I strongly recommend reading it, since it can clarify many questions you might have about the policy. If you’re writing a web service proxy and wants to attach a policy, there is no UI and you should know the policy name. Speaking of names, one good aspect is that OWSM policies are named in a very intuitive way. For example, wss11_saml_token_with_message_protection_client_policy says that it is a client policy implementing message protection for SAML 1.1 tokens. In other words, it adds an encrypted and signed SAML 1.1 token to the outgoing SOAP message.

OWSM Policies in Enterprise Manager

JDeveloper is not the single option for policy attachment. Organizations may decide to take such task off developers hands and defer it to sysadmins. That’s accomplished with Enterprise Manager. You navigate to the attachment point and simply pick the policy you want. Policy enforcement starts immediately.

Besides that, Enterprise Manager provides some very convenient ways for working with policies.
There’s a “Create Like” option serving as a template mechanism. During policy creation, you can change several attributes of the original policy as well as add, change or remove specific assertions. By the way, a policy is composed of one or more assertions, who are the ones that actually do the “heavy-lifting”, containing the necessary logic to deal with the SOAP message.

By saving the policy, it gets persisted into the policy repository.

You then have the option to export it to a file. This is useful if you want to consume it directly from the file system (as JDeveloper does by default) and want to add your own assertion implementation class (which is typically the case when you’re developing a custom policy).

When exporting the file, notice that Enterprise Manager messes up with the file name a bit, by changing the “/” (slash) symbol following the “oracle” prefix to an “_” (underscore). You must rename the file, by cutting “oracle_” off the file name. Then simply copy the file to the oracle folder under the gmds/owsm/policies folder mentioned before.

image

If you want to separate out the custom files from the ones shipped by Oracle, you can even create a new folder under gmds, say “custom”, and put your custom policy there. JDeveloper will automatically acknowledge that.

Another very interesting feature I should mention is that Enterprise Manager implements a web service client, allowing  OWSM policies to be tested. For example, let’s say you develop a pair of policies to implement WSS digest-based authentication. Upon attaching the service-side policy to your deployed web service, you should be able to use EM’s testing page to attach the client-side policy to the outgoing SOAP message and verify if your policies are ok.

Next time I will cover how to write custom OWSM policies, including the main java APIs developers should be aware of.

Using asymmetric cryptography in OWSM

Introduction

It has been somewhat a common practice replicating the same java key store across interacting WLS domains so that web services clients and web services can chat with message protection (WSS – Web Services Security). In that case, OWSM (Oracle Web Services Manager) is able to default to the private key stored in the key store to encrypt the symmetric key used for message encryption/decryption.

While that’s acceptable in developments environments, it might not be in production mode. Organizations may want to eliminate the risk of having the private key shared and compromised in distributed WLS deployments.

This article describes how that can be implemented in OWSM by examining the required OWSM configuration and two sample client applications: one Oracle ADF using a Web Service Data Control and one non-ADF using JAX-WS proxy.

Long story short: web services providers distribute their public key to consumers, who in turn explicitly refer to them when attaching OWSM client-side policies by overriding the keystore.recipient.alias property. Keep reading if you are interested in seeing how that is done.

Configuring the WLS domain hosting the web service

Let’s first understand how OWSM gets the services it needs to work with WSS.

OWSM relies on OPSS (Oracle Platform Security Services) configuration for its required services. By default, OWSM looks for the “default” jpsContext to get a hold of them. We’re interested in credstore and keystore services. OPSS configuration is held in jps-config.xml that sits in $DOMAIN_HOME/config/fmwconfig.

In the snippet below, we’re looking at the default jpsContext in jps-config.xml.

 
   1: <jpsContexts default="default">
   2:     <!-- This is the default JPS context. All the mendatory services and Login Modules must be configured in this default context -->
   3:     <jpsContext name="default">
   4:         <serviceInstanceRef ref="credstore"/>
   5:         <serviceInstanceRef ref="keystore"/>
   6:         <serviceInstanceRef ref="policystore.xml"/>
   7:         <serviceInstanceRef ref="audit"/>
   8:         <serviceInstanceRef ref="idstore.ldap"/>
   9:     </jpsContext>

Line 5 above tells OWSM to look for the keystore serviceInstance, which is out-of-box defined as:

 
   1: <!-- KeyStore Service Instance -->
   2:         <serviceInstance name="keystore" provider="keystore.provider" location="./default-keystore.jks">
   3:             <description>Default JPS Keystore Service</description>
   4:             <property name="keystore.type" value="JKS"/>
   5:             <property name="keystore.csf.map" value="oracle.wsm.security"/>
   6:             <property name="keystore.pass.csf.key" value="keystore-csf-key"/>
   7:             <property name="keystore.sig.csf.key" value="sign-csf-key"/>
   8:             <property name="keystore.enc.csf.key" value="enc-csf-key"/>
   9:         </serviceInstance>

It basically says that ./default-keystore.jks is the keystore file holding the certificate keys for WSS.

Likewise, line 6 in the first snippet informs OWSM on the credential store service. The credential store holds the credentials required for accessing the keystore as well as the aliases defined within it. Here’s how the cred store service is configured in jps-config.xml. Notice the location attribute. It points to the current directory. In reality, the credential store (as a file) is materialized as cwallet.sso file in that directory.

 
   1: <!-- JPS Credential Store Service Instance -->
   2:         <serviceInstance name="credstore" provider="credstoressp" location="./">
   3:             <description>File Based Credential Store Service Instance</description>
   4:         </serviceInstance>

Ok, basic OPSS configuration understood, let’s create an asymmetric key pair for the WLS server hosting the web service.

To execute the subsequent commands, have the keytool tool in your system path.

> keytool -genkeypair -keyalg RSA -alias orakey -keypass welcome1 -keystore default-keystore.jks -storepass welcome1 -validity 3600 

Now default-keystore.jks contains a self-signed certificate whose encrypting algorithm is RSA. RSA will be used for encrypting the symmetric key that encrypts the SOAP message.

Notice the storepass parameter value, which is welcome1. That defines the keystore password. Also notice the alias parameter and keystore parameter values. Those need to be properly seeded in the credential store. Please refer to this article on how to create them.

Next step is exporting the public key to a file.

> keytool -export -keystore default-keystore.jks -alias orakey -file server.crt

Such public key (server.crt) is the one that is distributed to everyone who wants to call in the WSS web services in this WLS domain.

Configuring the WLS domain hosting the web service client

The same jps-config.xml configuration applies to the WLS client domain. But in the client we just need to import the server.crt file containing the server public key into the key store.

> keytool -import -trustcacerts -alias server-public-cert -file server.crt -keystore default-keystore.jks

Notice the alias name: server-public-cert. It defines to where the public key is copied within the key store. You’ll need this name when overriding the keystore.recipient.alias property in the OWSM policy attachment in the web service client application.

Overriding the keystore.recipient.alias property

In this example, our client application is an ADF one that invokes the web service via an ADF Web Service Data Control. I won’t go into the details of defining the data control here. That’s something that can be found in the ADF Developers Guide available at OTN or in JDeveloper itself.

Once the data control is defined, follow these steps:

1 – In Applications Navigator, click the DataControls.dcx file:

showDataControl

2 – In the DataControls.dcx structure, right click the ADF Data Control Web Service and then click Define Web Service Security… option:

defineWSS

3 – In the Edit Data Control Policies window, choose oracle/wss11_username_token_with_message_protection_client_policy. It will allow the client to propagate a fixed identity to the web service at the same time providing WSS to the entire SOAP message. Take a bit of time to read the policy description. It is worth it.

Do notice that choosing such policy implies that the web service is configured with the corresponding OWSM server-side policy.

policyAttachment

4 – Click the Override Properties button.

The csf-key property defined the key in the credential store that holds the user to be propagated to the web service in the UsernameToken header.

In order to create it, execute the following wlst online command in the client WLS domain:

> createCred(map=”oracle.wsm.security”,key=”manager-key”,user=”my-wife”,password=”yesdear”)

If you click the New Key.. button, you have the opportunity to define it right here (thus avoiding the wlst command above) and it will be pushed to the WLS domain credential store when you deploy your application (this “pushing credentials”  feature can be disabled if you want).

keystore.recipient.alias is what we’re really interested in this article. It references the alias name for the server public key in the WLS client domain’s key store.

overridingProperties

What if my client application is a non-ADF one?

If you had a JAX-WS proxy in a non-ADF client application, this is how you would do it.

Notice line 25. There we’re overriding the keystore.recipient.alias.

   1:
   2: import java.net.MalformedURLException;
   3: import java.net.URL;
   4: import javax.xml.namespace.QName;
   5: import javax.xml.parsers.DocumentBuilderFactory;
   6: import javax.xml.ws.BindingProvider;
   7: import oracle.j2ee.ws.common.jaxws.ServiceDelegateImpl;
   8: import oracle.webservices.ClientConstants;
   9: import oracle.wsm.security.util.SecurityConstants;
  10: import org.w3c.dom.Element;
  11:
  12:         String endpoint = "http://127.0.0.1:7101/context-root/GreetingsAppModuleService";
  13:  
  14:         URL wsdlURL = new URL(endpoint+"?WSDL");
  15:  
  16:        ServiceDelegateImpl serviceDelegate = new ServiceDelegateImpl(wsdlURL, new QName("http://xmlns.oracle.com/trunk/owsm/", "GreetingsAppModuleService"), oracle.webservices.OracleService.class);
  17:        MyAppModuleService port = serviceDelegate.getPort(new QName("http://xmlns.oracle.com/trunk/owsm/", "GreetingsAppModuleServiceSoapHttpPort"), GreetingsAppModuleService.class );
  18:        
  19:         InputStream isClientPolicy = this.getClass().getResourceAsStream("client-policy.xml");
  20:        
  21:         try {
  22:           ((BindingProvider)port).getRequestContext().put(ClientConstants.CLIENT_CONFIG, fileToElement(isClientPolicy));
  23:           ((BindingProvider)port).getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, endpoint);
  24:           ((BindingProvider)port).getRequestContext().put(SecurityConstants.ClientConstants.WSS_CSF_KEY, "manager-key");
  25:           ((BindingProvider)port).getRequestContext().put(SecurityConstants.ClientConstants.WSS_RECIPIENT_KEY_ALIAS, "server-public-cert");
  26:         }
  27:         catch (Exception ex) {
  28:           ex.printStackTrace();
  29:         }
  30:        
  31:  
  32:         return port.sayHello(name);
  33:  
  34:     public static Element fileToElement(InputStream f) throws IOException, Exception {
  35:        DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
  36:        builderFactory.setValidating(false);
  37:        builderFactory.setNamespaceAware(true);
  38:        builderFactory.setIgnoringElementContentWhitespace(true);
  39:        builderFactory.setIgnoringComments(true);
  40:        return builderFactory.newDocumentBuilder().parse(f).getDocumentElement();
  41:     }

The client-policy.xml would be:

   1: <?xml version="1.0" encoding="UTF-8"?>
   2: <oracle-webservice-clients>
   3:    <webservice-client>
   4:        <port-info>
   5:            <policy-references>
   6:                <policy-reference uri="oracle/wss11_username_token_with_message_protection_client_policy" category="security"/>
   7:             </policy-references>
   8:        </port-info>
   9:    </webservice-client>
  10: </oracle-webservice-clients>

Conclusion

In this article I showed how to use real asymmetric cryptography in OWSM by examining the keystore configuration details and looked at how web services client applications should be configured to support it. I believe this is a very important topic, since it eliminates the risk of having a single private key shared across WLS domains that participates in web services interactions.

Hands-on WSRP Security in Oracle Fusion Middleware

Introduction

This article shows how to securely propagate a user identity to a portlet, have this identity asserted and authorized to view the portlet.

WSRP (Web Services Remote Portlets) are web services. In Oracle Fusion Middleware, the way of enabling identity propagation and authentication is via OWSM (Oracle Web Services Manager) policies. The concept is no different that securing any regular web service.

Portlets authorization is handled by the OPSS (Oracle Platform Security Services) layer once authentication is done.


Note: What follows has been implemented in Oracle Fusion Middleware 11g PS1 stack (JDeveloper, WLS, Web Center, OWSM and OPSS)


OWSM policies

OWSM  is the component that implements web services security and allows for runtime enforcement and declarative policy attachment within Oracle Fusion Middleware.

OWSM provides policies for different types of use case scenarios. For example, there are policies supporting SAML token profile, kerberos, WSS1.0, SSL, etc. I will soon write an article covering OWSM in detail.

For WSRP, let’s pick a SAML token profile with WSS1.0. It basically means that the portlet will require a SAML token in the incoming SOAP header and the whole message will be digitally signed and encrypted according to WSS1.0 standards.

On the portlet producer side, we’ll attach wss10_saml_token_with_message_protection_service_policy. And on the consumer side, we’ll attach wss10_saml_token_with_message_protection_client_policy.

The policy attached to the consumer adds the SAML token to the SOAP header and performs message signing/encryption. The policy attached to the provider verifies the signature, decrypts the message, retrieve the SAML token and delegates the assertion to the OPSS layer, which verifies its validity against the configured identity store.

Securing the Producer

Authentication

The policy wss10_saml_token_with_message_protection_service_policy needs to be attached to the portlet producer. Here I will show how to do it by updating oracle-webservices.xml. Do notice this can also be accomplished via Oracle Enterprise Manager.

oracle-webservices.xml is a packaging-time artifact, meaning it is not available in JDeveloper during design-time. Therefore, to edit the file, first deploy your application to an ear file, extract the file, update it and repackage it into the ear file.

The update itself is very simple. Look for port-component name=”WSRP_v2_Markup_Service” and add the highlighted snippet shown below:

<port-component name=”WSRP_v2_Markup_Service” style=”document”
                                  bindingQName=”{urn:oasis:names:tc:wsrp:v2:bind WSRP_v2_Markup_Binding_SOAP”
                                  enabled=”true”
                                  schemaValidateInput=”false”>
   
<policy-references>
     <policy-reference enabled=”true” 
                                       uri=”oracle/wss10_saml_token_with_message_protection_service_policy”
                                       category=”security”/>
   </policy-references>

   <operations>
     …
   </operations>
   <!– start:deployment time generated info –>
   <deployment>
    <tie-class-name>oasis.names.tc.wsrp.v2.bind.runtime.WSRP_v2_Markup_Binding_SOAP_Tie</tie-class-name>
    <service-qname namespaceURI=”urn:oasis:names:tc:wsrp:v2:wsdl”
localpart=”WSRP_v2_Service”/>
    <soap-version>soap1.1</soap-version>
   </deployment>
   <!– end:deployment time generated info   –>
   <servlet-link>WSRP_v2_Markup_Service</servlet-link>
 </port-component>


Note: The portlet producer application needs to be deployed in order to be called by consumers. You cannot “Click & Run” a secured portlet application from JDeveloper.


 

Key store and Credential store configuration

This is a necessary step only because the OWSM policies we’re using require message-level protection.

Both key store and credential store are WLS domain wide artifacts and WLS expects them to be found under $DOMAIN_HOME/config/fmwconfig folder.

In a nutshell, the key store contains the signing and encryption keys used to sign/encrypt/decrypt messages. Each key and the key store itself are password protected. They are also referred by an alias. These aliases and the corresponding passwords are stored in the credential store. When access to key store is required, the credential store is first queried for the necessary aliases and passwords.


Key store contents

The key store is created by using JDK’s keytool command. Assuming JDK is on your $PATH, type keytool in a command prompt and you will see the command options.

To list the contents of the key store, type:

keytool –list –v –keystore <keystore_filename> -storepass <keystore password>


How to create a certificate key

In order to protect the symmetric key used to actually encrypt the SOAP message, we need a PKI certificate in the key store. For the sake of this example, let’s have this certificate under an alias called “orakey”, with password equals to “welcome1”.

keytool -genkeypair -keyalg RSA -alias orakey -keypass welcome1 -keystore default-keystore.jks -storepass welcome1 -validity 3600


Note: JDK 6 is required to generate a key store compatible with OWSM in FMW 11g.


 

Credential store contents

A credential store is split into maps. Each map contains a set of keys. Each key points to the actual credential. The aliases created in the key store must have a corresponding credential in the credential store. For example, if we have named our alias as “orakey” in the key store, there must be a credential named “orakey” in the credential store. Such credential is pointed by a predefined key names.

For OWSM, these key names are sign-csf-key and enc-csf-key, which are used to sign and encrypt/decrypt messages. Another important key is keystore-csf-key, which holds the key store alias and password and is used to open the key store.

OWSM uses a predefined credential map named oracle.wsm.security.


How to populate the credential store

The credential store can be populated through WLST or Oracle Enterprise Manager.

In WLST, execute these online commands:

wls:/DefaultDomain/serverConfig> createCred(map=”oracle.wsm.security”, key=”keystore-csf-key”, user=”owsm”, password=”welcome1″, desc=”Keystore key”)
wls:/DefaultDomain/serverConfig> createCred(map=”oracle.wsm.security”, key=”enc-csf-key”, user=”orakey”, password=”welcome1″, desc=”Encryption key”)
wls:/DefaultDomain/serverConfig> createCred(map=”oracle.wsm.security”, key=”sign-csf-key”, user=”orakey”, password=”welcome1″, desc=”Signing key”)

Such commands update your domain level credential store. Normally, it corresponds to cwallet.sso under $DOMAIN_HOME/config/fmwconfig.


Verifying key store and credential store configuration in jps-config.xml

Open jps-config.xml located at $DOMAIN_HOME/config/fmwconfig and check whether the following entry exists. This should be out of box configured.

<serviceInstance location=”./” provider=”credstoressp” name=”credstore”> 
  <description>File Based Credential Store Service Instance</description>
 </serviceInstance>
 <serviceInstance name=”keystore” provider=”keystore.provider” location=”./default-keystore.jks”>
   <description>Default JPS Keystore Service</description>
   <property name=”keystore.type” value=”JKS”/>
   <property name=”keystore.csf.map” value=”oracle.wsm.security”/>
   <property name=”keystore.pass.csf.key” value=”keystore-csf-key”/>
   <property name=”keystore.sig.csf.key” value=”sign-csf-key”/>
   <property name=”keystore.enc.csf.key” value=”enc-csf-key”/>
 </serviceInstance>

Also, make sure the “default” context references the key store and credential store service instances above:

<jpsContext name=”default”>
   <serviceInstanceRef ref=”credstore”/>
   <serviceInstanceRef ref=”policystore.xml”/>
   <serviceInstanceRef ref=”audit”/>
   <serviceInstanceRef ref=”idstore.ldap”/>
   <serviceInstanceRef ref=”keystore”/>
 </jpsContext>

 


Note: If this configuration is already in place, you don’t need to restart your WLS domain. Otherwise, make the changes and restart your WLS domain.


 

Authorization

Portlets authorization is delegated to OPSS layer, i.e., the decision whether or not a portlet is available to a user is done against the OPSS policy store. Portlets are just one way of exposing local ADF task flows to remote applications. There’s a component called portlet brigde that is responsible for providing the glue between portlets and task flows. It basically makes possible exposing a task flow as a portlet.

In the example below, the policy store is file-based. Normally it is represented by system-jazn-data.xml located under $DOMAIN_HOME/config/fmwconfig folder. That can be easily changed to be and LDAP-based one.

Once the right task flow permissions are already in place in the policy store, there’s only one more permission that needs to be added, and it should be granted to the authenticated-role:

<permission> 
  <class>oracle.adf.controller.security.TaskFlowPermission</class>
   <name>/WEB-INF/adfp-portlet-bridge-container.xml#adfp-portlet-bridge-container</name>
   <actions>view</actions>
 </permission>

Here’s an example of a complete set of grants required for portlet authorization. In the example, the propagated user must be granted approle1 application role in order to view the portlet (assuming /WEB-INF/my-task-flow.xml#my-task-flow is taskflow exposed as a portlet).

<jazn-policy> 
  <grant>
     <grantee>
       <principals>
         <principal>
           <class>oracle.security.jps.internal.core.principals.JpsAuthenticatedRoleImpl</class>
           <name>authenticated-role</name>
         </principal>
       </principals>
     </grantee>
     <permissions>
       <permission>
         <class>oracle.adf.controller.security.TaskFlowPermission</class>
         <name>/WEB-INF/adfp-portlet-bridge-container.xml#adfp-portlet-bridge-container</name>
         <actions>view</actions>
       </permission>
     </permissions>
   </grant>
   <grant>
     <grantee>
       <principals>
         <principal>
           <class>oracle.security.jps.service.policystore.ApplicationRole</class>
           <name>approle1</name>
         </principal>
       </principals>
     </grantee>
     <permissions>
       <permission>
         <class>oracle.adf.controller.security.TaskFlowPermission</class>
         <name>/WEB-INF/my-task-flow.xml#my-task-flow</name>
         <actions>view</actions>
       </permission>
     </permissions>
   </grant>
 </jazn-policy>

Securing the Consumer

Securing a portlet consumer basically means enabling identity propagation. This is done during portlet producer registration in JDeveloper. When doing it, make sure you select/enter the right information in step 5 at WSRP Portlet Producer Registration wizard, as shown below:


Note: the configuration made here is written to connections.xml


 

Key store and Credential store configuration

Within the portlet consumer WLS domain, both key store and credential store can be the same used by the portlet producer. Have them at $DOMAIN_HOME/config/fmwconfig, as explained previously.

It is true we have a potential security issue here, since the certificates used by WSS are the same across WLS domains, and I’ll cover how to harden it in a next article.

Identity Propagation in a flow involving OAM, OSB and web services

A Sales Consultant asked for my opinion in a scenario where a customer wants to propagate end user credentials all the way from OAM (Oracle Access Manager) to web services responsible for executing business logic.In the customer flow, after being authe…

OWSM Client Policies and SAML – Simpler is Better

Classic example of me being “too clever by half”.

From the OWSM Documentation

Looks like you can just set the username as a property


URL localURL =
new URL("https://.../MyWebServicePort?WSDL");

QName name = new QName("http://view.team2.oracle.com/","MyWebServiceService");

myWebServiceService =
new MyWebServiceService(localURL,name);

final weblogic.wsee.jws.jaxws.owsm.SecurityPolicyFeature securityFeature =
new weblogic.wsee.jws.jaxws.owsm.SecurityPolicyFeature("policy:oracle/wss_saml_token_bearer_over_ssl_client_policy");

WebServiceFeature[] features =
new WebServiceFeature[] {securityFeature};

MyWebService myWebService =
myWebServiceService.getMyWebServicePort(features);


Map<String,Object> reqContext = ((BindingProvider) myWebService).getRequestContext();
reqContext.put( BindingProvider.USERNAME_PROPERTY, "jdoe");


// Add your code to call the desired methods.
System.out.println(myWebService.helloThere("From a Java client - JDOE"));

This “AH HA” eliminates the need for the code to get the JAAS Subject and the configuration of the jps-config.xml and system-jazn-data.xml. Much better.

Just to round out, here is the client for SAML sender-vouches.


URL localURL = new URL("http://oamwindows:7001/Team2-ViewController-context-root/MyWebServicePort?WSDL");

QName name = new QName("http://view.team2.oracle.com/","MyWebServiceService");

myWebServiceService =
new MyWebServiceService(localURL,name);

final weblogic.wsee.jws.jaxws.owsm.SecurityPolicyFeature securityFeature =
new weblogic.wsee.jws.jaxws.owsm.SecurityPolicyFeature("policy:oracle/wss10_saml_token_with_message_integrity_client_policy");

WebServiceFeature[] features =
new WebServiceFeature[] {securityFeature};

MyWebService myWebService =
myWebServiceService.getMyWebServicePort(features);

Map<String,Object> reqContext = ((BindingProvider) myWebService).getRequestContext();
reqContext.put( BindingProvider.USERNAME_PROPERTY, "jdoe");


reqContext.put(ClientConstants.WSSEC_KEYSTORE_LOCATION, "c:/wstest/alice.jks");
reqContext.put(ClientConstants.WSSEC_KEYSTORE_PASSWORD, "password" );
reqContext.put(ClientConstants.WSSEC_SIG_KEY_ALIAS, "alice" );
reqContext.put(ClientConstants.WSSEC_KEYSTORE_TYPE, "JKS" );
reqContext.put(ClientConstants.WSSEC_SIG_KEY_PASSWORD, "password" );
reqContext.put(ClientConstants.WSSEC_ENC_KEY_ALIAS, "alice" );
reqContext.put(ClientConstants.WSSEC_ENC_KEY_PASSWORD, "password" );
reqContext.put(ClientConstants.WSSEC_RECIPIENT_KEY_ALIAS,"bob");

System.out.println(myWebService.helloThere("From a Java client"));

I did all of my testing with the demo CA that ships with WebLogic Server. I find the CertGen and the ImportPrivateKey
tools to be really useful in building small samples. I created two keystores – alice.jks and bob.jks. Alice for the client and Bob for the server. This is all standard stuff, but one thing to remember that OWSM has only a single identity and trust store…not separate stores as in J2SE or WLS, so I had to add the CertGenCA.der to both keystores.

Beyond on that, really pretty simple. I configured the bob.jks keystore for the WebLogic Server Domain from EM – Domain (Right Click) -> Security -> Security Provider Configuration. Scroll down to Keystore…configure bob.jks as the store. Restart the server. Send the message and it just works!

OWSM stand-alone Client to OWSM Server doing SAML Bearer and SAML Sender-Vouches – check!

SAML Bearer Confirmation – An example using OWSM Client Policy

This is an extension of the discussion started by Brian in his inaugural post here at the FusionSecurity blog. Brian and I, along with other members of the A-Team were out at HQ getting some training on the SOA Security capabilities in 11g, and I wante…