What this example will demonstrate is how to use the credential store to store and retrieve a password for a given key in a given map.
First to get started, some JAR files from the Oracle Fusion Middleware is required. The easiest way is to get these is to install JDeveloper 11g. Below is a list of files needed to be on the classpath for the project (these are located in Middleware/oracle_common/modules):
- oracle.idm_11.1.1/identitystore.jar
- oracle.osdt_11.1.1/osdt_cert.jar
- oracle.osdt_11.1.1/osdt_core.jar
- oracle.osdt_11.1.1/osdt_xmlsec.jar
- oracle.pki_11.1.1/oraclepki.jar
- oracle.jps_11.1.1/jacc-spi.jar
- oracle.jps_11.1.1/jps-api.jar
- oracle.jps_11.1.1/jps-az-api.jar
- oracle.jps_11.1.1/jps-az-common.jar
- oracle.jps_11.1.1/jps-az-management.jar
- oracle.jps_11.1.1/jps-az-rt.jar
- oracle.jps_11.1.1/jps-ee.jar
- oracle.jps_11.1.1/jps-common.jar
- oracle.jps_11.1.1/jps-internal.jar
- oracle.jps_11.1.1/jps-pep.jar
- oracle.jps_11.1.1/jps-se.jar
- oracle.jps_11.1.1/jps-unsupported-api.jar
Next thing to do is set the Java options for running the compiled code like this:
-Doracle.security.jps.config=./jps-config-jse.xml -Djava.security.debug=off
The debug setting can be set to 'all' to see exactly what CSF is doing, that tends to produce quite a lot of output, so I've turned it off.
Now the jps-config-jse.xml file needs to be created. The official documentation does not provide a full example of this, but there is an example of this file in the JDeveloper directories, I used that to create the file below.
<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 jps-config-11_1.xsd"
schema-major-version="11"
schema-minor-version="1">
<property name="oracle.security.jps.jaas.mode" value="off"/>
<serviceProviders>
<serviceProvider type="CREDENTIAL_STORE" name="credstoressp" class="oracle.security.jps.internal.credstore.ssp.SspCredentialStoreProvider">
<description>SecretStore-based CSF provider</description>
</serviceProvider>
<serviceProvider type="POLICY_STORE" name="policystore.xml.provider" class="oracle.security.jps.internal.policystore.xml.XmlPolicyStoreProvider">
<description>XML-based PolicyStore Provider</description>
</serviceProvider>
</serviceProviders>
<serviceInstances>
<serviceInstance name="credstore" provider="credstoressp" location="./">
<description>File Based Credential Store Service Instance</description>
</serviceInstance>
<serviceInstance name="policystore.xml" provider="policystore.xml.provider" location="./system-jazn-data.xml">
<description>File Based Policy Store Service Instance</description>
</serviceInstance>
</serviceInstances>
<jpsContexts default="default">
<jpsContext name="default">
<serviceInstanceRef ref="credstore"/>
<serviceInstanceRef ref="policystore.xml"/>
</jpsContext>
</jpsContexts>
</jpsConfig>
What the file does is tell CSF to create a credential store and a policy store. The policy store is not actually used, but the code was throwing exceptions without it so I added it in. The location of the wallet file will be in the same directory as the config file with the above setup.
The file above also references system-jazn-data.xml, so that needs to be created. There is no setup required for our purposes in that file, so it's contents are just this:
<jazn-data/>
Now that the config is done, I used the example CsfUtil class and modified it to store one single password credential in the map called 'pc_map' for the key called 'pc_key'. The code is really quite simple.
import java.security.AccessController;
import java.security.PrivilegedAction;
import oracle.security.jps.JpsException;
import oracle.security.jps.service.credstore.CredentialAlreadyExistsException;
import oracle.security.jps.service.credstore.CredentialFactory;
import oracle.security.jps.service.credstore.CredentialStore;
import oracle.security.jps.service.credstore.PasswordCredential;
public class CsfUtil {
final CredentialStore store;
public CsfUtil(CredentialStore store) {
super();
this.store = store;
}
private void doOperation() {
try {
PasswordCredential pc = null;
try {
pc = (PasswordCredential)store.getCredential("pc_map", "pc_key");
if (pc == null) {
// key not found, create one
pc = CredentialFactory.newPasswordCredential("jdoe",
"password".toCharArray());
// this call requires write privilege
store.setCredential("pc_map", "pc_key", pc);
System.out.print("Created ");
}
else {
System.out.print("Found ");
}
System.out.println("password credential: Name=" + pc.getName() +
",Password=" +
new String(pc.getPassword()));
} catch (CredentialAlreadyExistsException e) {
// ignore since credential already exists.
System.out.println("Credential already exists for <pc_map, pc_key>: " + pc.getName() + ":" +
new String(pc.getPassword()));
}
} catch (JpsException e) {
e.printStackTrace();
}
}
/*
* Since this method performs a privileged operation, only current class or
* jar containing this class needs CredentialAccessPermission
*/
public void doPrivilegedCredOperation() {
AccessController.doPrivileged(new PrivilegedAction<String>() {
public String run() {
doOperation();
return "done";
}
});
}
}
I created a separate class as per the official documentation to call the utility code. This class was as follows:
import oracle.security.jps.JpsContext;
import oracle.security.jps.JpsContextFactory;
import oracle.security.jps.JpsException;
import oracle.security.jps.service.credstore.CredentialStore;
public class Environment {
// set the OPSS policy provider explicitly, as required in a Java SE application
static {
java.security.Policy.setPolicy(new oracle.security.jps.internal.policystore.JavaPolicyProvider());
}
public static void main(String[] a) {
JpsContextFactory ctxFactory;
try {
ctxFactory = JpsContextFactory.getContextFactory();
JpsContext ctx = ctxFactory.getContext();
CredentialStore store = ctx.getServiceInstance(CredentialStore.class);
CsfUtil csf = new CsfUtil(store);
csf.doPrivilegedCredOperation();
} catch (JpsException e) {
e.printStackTrace();
}
}
}
That's it! First time this code runs it creates the cwallet.sso file, which is the Oracle Wallet. The second time the code is run, it fetches the password out of the wallet.
-i