With custom assertions you can create your own specific policies. There are a number of out-of-the box policy implementations already available implementing most of the common WS Security profiles and other non-security related policies like logging. If you want to create your own security policy one of the things you need is access to the credential store and keystore. There is some sample code on how to access the credential store. Unfortunately I could not find any sample code on how to access the keystore. In this blog I will show you how I implemented this using some of the available but not well documented Oracle utility classes.
The thing I want to do is:
Generate an abstract Assertion class that will give me the following basic functionality:
a)Â Property handling:Â My assertion will have properties I can set at the policy administration inside Enterprise Manager (EM). Setting properties there means their values will be the basic setting whenever a assertion is attached to a web service. I will call this design time. These property values can be overwritten when the assertion is actually assigned to a web service, for example in OSB. I will call this runtime overwriting. Â This class will need to handle this.
b) Keystore access: Â I want to be able to get private and public keys from the keystore I configured in EM. Â One of my assertion properties will be a csf-key that contains the alias and password of the private key I will be using to sign (or encrypt I am not sure yet what I want my custom assertion to do) the web service SOAP message. So I will need to access the credential store also. Preferably through the jpsManager. Â This is a utility class that can access the keystore configuration and credential store. Browsing through the oracle code this looks like the preferred way to do this.
The jpsManager has some useful methods to access the jps-config.xml file and the credential store:
method | description |
---|---|
setAuthenticationMode | You need to set this before you can use the jpsManager. I used the value anonymous. |
getKeyStoreLevelCredentialStore | Retrieves an instance of the credential store needed to get the csf-key values. |
getKeyStoreConfig | Get the keystore configuration as it is configured inside the jps-config.xml file. |
Browsing through the oracle classes I found the oracle.wsm.security.policy.scenario.util.ScenarioUtils
utility class offering some nice methods I can use as well:
method | description |
---|---|
isJpsEnv | used to check whether the jps configuration is active in this environment |
getKeyStoreCredsFromCSF | gets the username and password from the credential store using a csf-key |
getConfigPropertyValue | Retreives the value of a property. To do this it looks inside the MessageContext first. So it retrieves the runtime value first. Secondly it looks inside the design time properties, the properties that were loaded at initalization. Finally it looks in the jps configuration retrieved from the jps-config.xml. |
getConfigPropertyRecipientCert | Specialized version of the function above. This actually gets a certificate ‘object’. |
In the init
method of the CustomAssertion class an instance of the jpsManager is created. Secondly the design time assertion properties are loaded.
Each time this assertion is execute an instance of a WsmKeyStore is created. The instance needs to be created there as the csf-key for the signing and encryption alias/password credentials can be overwritten at runtime. The method that handles the retrieval of all parameters needed to create a WsmKeyStore and finally creating the instance is the setWsmStore
method.
This results in the following:
package nl.amis.custompolicy; import java.security.cert.X509Certificate; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.logging.Level; import java.util.logging.Logger; import javax.xml.namespace.NamespaceContext; import javax.xml.xpath.XPath; import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathExpressionException; import javax.xml.xpath.XPathFactory; import oracle.security.jps.service.credstore.CredentialStore; import oracle.wsm.common.sdk.IContext; import oracle.wsm.common.sdk.IMessageContext; import oracle.wsm.common.sdk.WSMException; import oracle.wsm.policy.model.IAssertion; import oracle.wsm.policy.model.IAssertionBindings; import oracle.wsm.policy.model.IProperty; import oracle.wsm.policy.model.impl.Config; import oracle.wsm.policy.model.impl.SimpleAssertion; import oracle.wsm.policyengine.IExecutionContext; import oracle.wsm.policyengine.impl.AssertionExecutor; import oracle.wsm.security.SecurityException; import oracle.wsm.security.jps.JpsManager; import oracle.wsm.security.jps.WsmKeyStore; import oracle.wsm.security.jps.WsmKeyStoreFactory; import oracle.wsm.security.policy.scenario.util.ScenarioUtils; import oracle.wsm.security.policy.scenario.util.ScenarioUtils.Credentials; import org.w3c.dom.Element; import org.w3c.dom.Node; public abstract class CustomAssertion extends AssertionExecutor { private static final String CLASSNAME = CustomAssertion.class.getName(); private static final Logger TRACE = Logger.getLogger(CLASSNAME); protected IAssertion mAssertion = null; protected IExecutionContext mEcontext = null; protected IContext mIcontext = null; private JpsManager jpsManager; private WsmKeyStore wsmKeyStore; private Properties configProps; public CustomAssertion(String tag) { jpsManager = null; wsmKeyStore = null; configProps = new Properties(); } public void destroy() { } public JpsManager getJpsManager() { return jpsManager; } public WsmKeyStore getWsmKeyStore() { return wsmKeyStore; } public Properties getConfigProperties() { return configProps; } public void init(IAssertion iAssertion, IExecutionContext iExecutionContext, IContext iContext) throws WSMException { mAssertion = iAssertion; mEcontext = iExecutionContext; mIcontext = iContext; try { if (ScenarioUtils.isJpsEnv()) { jpsManager = new JpsManager(); jpsManager.setAuthenticationMode("anonymous"); } } catch (SecurityException e) { throw new WSMException(e); } IAssertionBindings bindings = ((SimpleAssertion)(this.mAssertion)).getBindings(); if (bindings != null) { List cfgl = bindings.getConfigs(); if (!cfgl.isEmpty()) { Config cfg = (Config)cfgl.get(0); List<IProperty> configProperties = cfg.getProperties(); if (configProperties != null) { for (IProperty configProperty : configProperties) { String propName = configProperty.getName(); String propValue = configProperty.getValue(); if (propValue == null || propValue.trim().isEmpty()) propValue = configProperty.getDefaultValue(); if (propValue != null) configProps.setProperty(propName, propValue); } } } } } protected boolean setWsmKeyStore(IMessageContext msgContext) throws SecurityException { // Retrieve Credential Store CredentialStore credentialStore = jpsManager.getKeyStoreLevelCredentialStore(); if (credentialStore == null) { throw new SecurityException("credentialstore not available Error"); } // Retreive KeyStore Configuration from jps-config.xml Map<String,String> keyStoreConfig = jpsManager.getKeyStoreConfig(); if (keyStoreConfig == null) { throw new SecurityException("keystore configuration not available Error"); } // Retreive Keystore Type from KeyStore Configuration String keystoreType = keyStoreConfig.get("keystore.type"); if (keystoreType != null && keystoreType.trim().isEmpty()) { throw new SecurityException("keystore type not set Error"); } if (!WsmKeyStore.KEYSTORE_TYPES_ENUM.JKS.toString().equalsIgnoreCase(keystoreType)) { throw new SecurityException("Only keystore of type JKS is supported"); } // Retrieve Keystore location from KeyStore Configuration String location = keyStoreConfig.get("location"); if (location != null && location.trim().isEmpty()) { throw new SecurityException("keystore location not set Error"); } // Retrieve Keystore CSF Map from KeyStore Configuration String keystoreCSFMap = keyStoreConfig.get("keystore.csf.map"); if (keystoreCSFMap != null && keystoreCSFMap.trim().isEmpty()) { throw new SecurityException("Keystore CSF Map not set Error"); } // Retrieve Keystore csf key from KeyStore Configuration String keyStorePassCSFKey = keyStoreConfig.get("keystore.pass.csf.key"); // Retrieve Keystore password from credential Store String keyStorePassword = null; if (keyStorePassCSFKey != null ) { Credentials keystorePassCreds = ScenarioUtils.getKeyStoreCredsFromCSF(keystoreCSFMap, keyStorePassCSFKey, credentialStore); if (keystorePassCreds!= null) keyStorePassword = new String(keystorePassCreds.getPassword()); } // Retrieve signature csf key from KeyStore Configuration or design time or runtime properties String keystoreSigCSFKey = ScenarioUtils.getConfigPropertyValue("keystore.sig.csf.key", msgContext, getConfigProperties(), keyStoreConfig); if (keystoreSigCSFKey != null && keystoreSigCSFKey.trim().isEmpty()) { throw new SecurityException("signature csf key is empty"); } // Retrieve signature alias and password from credential store String signAlias = null; String signPassword = null; Credentials signCreds = ScenarioUtils.getKeyStoreCredsFromCSF(keystoreCSFMap, keystoreSigCSFKey, credentialStore); if (signCreds != null) { signPassword = new String(signCreds.getPassword()); signAlias = signCreds.getUsername(); } // Retrieve encryption csf key from KeyStore Configuration or design time or runtime properties String keystoreEncCSFKey = ScenarioUtils.getConfigPropertyValue("keystore.enc.csf.key", msgContext, getConfigProperties(), keyStoreConfig); if (keystoreEncCSFKey != null && keystoreEncCSFKey.trim().isEmpty()) { throw new SecurityException("encryption csf key is empty"); } // Retrieve encryption alias and password from credential store String cryptAlias = null; String cryptPassword = null; Credentials cryptCreds = ScenarioUtils.getKeyStoreCredsFromCSF(keystoreCSFMap, keystoreEncCSFKey, credentialStore); if (cryptCreds != null) { cryptPassword = new String(cryptCreds.getPassword()); cryptAlias = cryptCreds.getUsername(); } // Retrieve receipiant certificate from design time or run time properties X509Certificate recipientCert = ScenarioUtils.getConfigPropertyRecipientCert(msgContext, getConfigProperties(), null); // Retrieve receipient alias from design time or runtime properties String keystoreRecipientAlias = ScenarioUtils.getConfigPropertyValue("keystore.recipient.alias", msgContext, getConfigProperties(), null); if (keystoreRecipientAlias != null && keystoreRecipientAlias.trim().isEmpty()) { throw new SecurityException("recipient alias is empty"); } wsmKeyStore = WsmKeyStoreFactory.getKeyStore(location, keystoreType, "keystore", keyStorePassword, signAlias, signPassword, cryptAlias, cryptPassword, keystoreRecipientAlias, recipientCert); return wsmKeyStore != null; } public static Node getDataNode(Element payload,final HashMap<String, String> namespaces,String xpathStr) { Node node = null; try { NamespaceContext ctx = new NamespaceContext() { public String getNamespaceURI(String prefix) { return namespaces.get(prefix); } public Iterator getPrefixes(String val) { return null; } public String getPrefix(String uri) { return null; } }; XPathFactory xpathFact = XPathFactory.newInstance(); XPath xpath = xpathFact.newXPath(); xpath.setNamespaceContext(ctx); node = (Node)xpath.evaluate(xpathStr, payload, XPathConstants.NODE); } catch (XPathExpressionException ex) { ex.printStackTrace(); return null; } return node; } return node; } }
In my next post I will create the actual assertion itself. I will create WS Security headers using Oracle utility classes for WS Security.
Dear Izaac: I have tried use your example in 11.1.1.3 OSB, but I can not find ‘o
racle.wsm.security.jps.WsmKeyStoreFactory' class. What version in OSB are you using?
Dear Izaac: Your post is very useful and I have used it in order to develop my own assertions. Do you know if is it possible to access to the trasport headers (user transport headers apart from Content-Type, SOAPAction, etc) Â from the request from a custom assertion?