Showing posts with label Security. Show all posts
Showing posts with label Security. Show all posts

Thursday, October 27, 2011

Oracle SOA 11g : Securing and Calling Secured Web Services (Example)

In Oracle Fusion Middleware 11g , Oracle Web Services Manager (WSM) security and management has been completely redesigned and rearchitected. The previous release, Oracle WSM 10g, was delivered as a standalone product or as a component of the Oracle SOA Suite. In the 11g release, Oracle WSM has been integrated with Oracle WebLogic Server as part of the Oracle Fusion Middleware SOA Suite.

In this post, I would explain how WSM integration can be used to secure a composite and also how to invoke a secured composite/ webservice. In order to accomplish it, let's create 2 composite projects:

- Child Process (secured composite): This composite has a simple BPEL project that accepts a string and returns the same string with "Hello " appended.

- Parent Process (unsecured composite calling the Child Process): This composite has a BPEL process that accepts the string, invokes the Child Process passing the input string and returns the output from the Child Process back to the calling interface.

I am skipping the development of the child and parent processes/composites as it is very simple and will detail how to configure Policies as below:

- Child Process:

Step1: Go to composite.xml and right click on the Exposed Services and click "Configure WS Policies" as below:


Step2: You can configure the policy pipeline but for the sake of simplicity, I will only configure the Security using the "oracle/wss_username_token_service_policy" as shown below:


Step3: Deploy the composite and test it using the em console. Remember now the composite is secured and requires a username token as part of the SOAP Header as below:

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Header>
<wsse:Security soap:mustUnderstand="1"
xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<wsse:UsernameToken xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
wsu:Id="UsernameToken-FvmfJSSMf71Q3Z9gn4chiQ22"
xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<wsse:Username>weblogic</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">welcome1</wsse:Password>
</wsse:UsernameToken>
</wsse:Security>
</soap:Header>
<soap:Body xmlns:ns1="http://xmlns.oracle.com/SecurityApplication_jws/ChildProcess/SecuredSvc">
<ns1:process>
<ns1:input>Neeraj</ns1:input>
</ns1:process>
</soap:Body>
</soap:Envelope>

Either modify the SOAP packet as above in the XML View or use the WSS UserName Token under Security configuration as below:


Parent Process:

Step 1: Go to composite.xml and right click on the External References (Child Process) and click on "Configure WS Policies". Select the "oracle/wss_username_token_client_policy" policy under security.

Step 2: Open the composite.xml in Source view and add the following properties under <reference> tag as below:

<reference name="SecuredBPEL"
:
:
<wsp:PolicyReference URI="oracle/wss_username_token_client_policy"
orawsp:category="security" orawsp:status="enabled"/>
<property name="weblogic.wsee.wsat.transaction.flowOption"
type="xs:string" many="false">WSDLDriven</property>
<property name="oracle.webservices.auth.username" type="xs:string"
many="false" override="may">weblogic</property>
<property name="oracle.webservices.auth.password" type="xs:string"
many="false" override="may">welcome1</property>
</binding.ws>
</reference>

Make sure the username and password is same as configured in the Weblogic Server.

Step3: Test the Parent process and it should be able to invoke the secured child process.

Few things to note:

1. All the above policy configurations can be done at runtime using the EM console without doing anything at the design time.

2. In the above example, we have hard-coded the username/password at development which should be made configurable as mentioned below:

- Go to EM console and right click on ParentProcess ->Service/Reference Properties -> PartnerLink -> Enter the username and password for the Child service in the below screen

Monday, August 1, 2011

Coherence Security using Access Controller

A detailed understanding of the Clustered Access Controller and Coherence is available here. Though steps for configuring Default Access Controller are available on the Coherence website but step-by-step guide on how to use it in real world is mentioned below:

*********************
Step 1: Create a class MyAccessController that implements AccessController Interface. The methods that should be implemented are:

- checkPermission(ClusterPermission clusterPermission, Subject subject)
The checkPermission method is used to authorise the security credentials of the subject for a particular action such as, join, create or destroy a clustered cache.

- SignedObject encrypt(Object object, Subject subject)
Encrypts the specified object using the private key extracted from the keystore specified in the constructor for MyAccessController.

- Object decrypt(SignedObject signedObject, Subject subject, Subject subject2)
Decrypts the specified SignedObject using the public credentials extracted from the keystore specified in the constructor for MyAccessController.

- Constructor: public MyAccessController(String keyStoreName, String alias,String password, File permissionFile)
* @param keyStoreName: File location of the keyStore
* @param alias: The Alias whose keys will be used
* @param password: The Password for the Alias
* @param permissionFile: The Permissions granted to the Alias

The complete class Implementation of the MyAccessController is as below:

public class MyAccessController implements AccessController {

/**
* The Default Controller will be used to implement the check permissions method
*/
public static DefaultController defaultController;

/** This is the signature algorithm that will be used with
* our keys to encrypt and decrypt SignedObject instances.
*/
public static final String SIGNATURE_ALGORITHM = "SHA1withDSA";

/** The PrivateKey used for encryption
*/
private PrivateKey privateKey;

/** The public key used for decryption
*/
private PublicKey publicKey;


public MyAccessController() {
super();
}

/*** Create a new ClusterAccessController using the keys
* * from the specified keystore.
* @param keyStoreName
* @param alias
* @param password
* @param permissionFile
*/

public MyAccessController(String keyStoreName, String alias,String password, File permissionFile) {

try {
// Extract the keys from the keystore
InputStream fileStoreStream;

File f = new File(keyStoreName);

if (f.exists()) {
fileStoreStream = new FileInputStream(f);
} else {
fileStoreStream =getClass().getResourceAsStream(keyStoreName);
}

if (fileStoreStream == null) {
throw new IllegalArgumentException("keystore file does not exist");
}

KeyStore store = KeyStore.getInstance("JKS");
store.load(fileStoreStream, null);
//Extract the Private Key for the Alias
privateKey =(PrivateKey) store.getKey(alias, password.toCharArray());
//Extract the Public Key for the Alias
publicKey = store.getCertificate(alias).getPublicKey();
//Intialize the Default Controller for implementing checkPermission method
defaultController = new DefaultController(f,permissionFile);
} catch (Exception e) {
if (e instanceof RuntimeException) {
throw (RuntimeException) e;
}
throw Base.ensureRuntimeException(e,"Error in ConfigurableClusterAccessController constructor");
}
}

/**
* @param clusterPermission
* @param subject
*/
@Override
public void checkPermission(ClusterPermission clusterPermission, Subject subject) {
//Implement your authoriation module or use the deafult Controller modeule
//based on the permissions file.
defaultController.checkPermission(clusterPermission, subject);
}

/**
* @param object
* @param subject
* @return
* @throws IOException
* @throws GeneralSecurityException
*/
@Override
public SignedObject encrypt(Object object, Subject subject) throws IOException, GeneralSecurityException {
return new SignedObject((Serializable) object, privateKey, Signature.getInstance(SIGNATURE_ALGORITHM));
}

/**
* @param signedObject
* @param subject
* @param subject2
* @return
* @throws ClassNotFoundException
* @throws IOException
* @throws GeneralSecurityException
*/
@Override
public Object decrypt(SignedObject signedObject, Subject subject, Subject subject2)
throws ClassNotFoundException,
IOException,
GeneralSecurityException {
if (!signedObject.verify(publicKey, Signature.getInstance(SIGNATURE_ALGORITHM))) {
throw new SignatureException("Unable to verify SignedObject");
}
return signedObject.getObject();
}
}

*********************
Step 2: Create the keystore.jks using java keytool utility for various aliases:

keytool -genkey -v -keystore <keystore.jks file location> -storepass password -alias admin
-keypass password -dname CN=Administrator,O=MyCompany,L=MyCity,ST=MyState

keytool -genkey -v -keystore <keystore.jks file location> -storepass password -alias manager
-keypass password -dname CN=Manager,OU=MyUnit

keytool -genkey -v -keystore <keystore.jks file location> -storepass password -alias worker
-keypass password -dname CN=Worker,OU=MyUnit

*********************
Step 3: Create a permission file as mentioned below:

<?xml version='1.0'?>
<permissions>
<grant>
<principal>
<class>javax.security.auth.x500.X500Principal</class>
<name>CN=Manager,OU=MyUnit</name>
</principal>

<permission>
<target>*</target>
<action>all</action>
</permission>
</grant>

<grant>
<principal>
<class>javax.security.auth.x500.X500Principal</class>
<name>CN=Worker,OU=MyUnit</name>
</principal>

<permission>
<target>cache=common*</target>
<action>join</action>
</permission>
<permission>
<target>service=invocation</target>
<action>all</action>
</permission>
</grant>
</permissions>

The above permission file is configured to allow managers to perform all the actions and the workers to join cache starting with name "common" and the invocation services.

*********************
Step 4: Create a JAAS configuration file coherence-jass.config as below:

// LoginModule Configuration for Oracle Coherence(TM)
Coherence {
com.tangosol.security.KeystoreLogin required
keyStorePath="<keystore.jks file location>
};

*********************
Step 5: Modify the tangosol-coherence-override.xml file to include:
<security-config>
<!-- Security is defaulted to true -->
<enabled system-property="tangosol.coherence.security">true</enabled>
<!-- The name of the JAAS login module to use - This is still the same as the Coherence default -->
<login-module-name system-property="coherence.security.loginmodule">Coherence</login-module-name>
<!-- Configure the access controller to use to authorise cluster membership -->
<access-controller>
<class-name>com.sample.MyAccessController</class-name>
<init-params>
<init-param id="1">
<param-type>java.lang.String</param-type>
<param-value>C:\Oracle\Coherence\Files\Security\Manager\keystore.jks</param-value>
</init-param>
<init-param id="2">
<param-type>java.lang.String</param-type>
<param-value>manager</param-value>
</init-param>
<init-param id="3">
<param-type>java.lang.String</param-type>
<param-value>password</param-value>
</init-param>
<init-param id="4">
<param-type>java.io.File</param-type>
<param-value system-property="tangosol.coherence.security.permissions">C:\Oracle\Coherence\Files\Security\permission.xml</param-value>
</init-param>

</init-params>
</access-controller>
<callback-handler>
<class-name>com.sun.security.auth.callback.TextCallbackHandler</class-name>
</callback-handler>
</security-config>

*********************
Step 6: When DefaultCacheServer runs it contains a loop that periodically calls CacheFactory.ensureService for each service that is configured with autostart=true and this loop runs every few seconds. As the ensureService call needs to be secured Coherence will call our Login Module to obtain credentials for each service in each loop. The solution to this is to run DefaultCacheServer itself with credentials already applied; i.e. wrap it inside a PrivilegedAction as mentioned below:

/* This class is
a wrapper around {@link com.tangosol.net.DefaultCacheServer} and will
* run a normal Coherence Cache Server wrapped in a {@link java.security.PrivilegedExceptionAction}
* and hence withing the scope of a {@link javax.security.auth.Subject}.
*
* @author Neeraj Jain
*/
public class JaasDefaultCacheServer {

static Subject subject;

/**
* @param args
* @throws Exception
*/
public static void main(final String[] args) throws Exception {
JaasDefaultCacheServer.startMain(args);
}

/**
* @throws Exception
*/
public static void start() throws Exception {
Security.runAs(subject, new PrivilegedExceptionAction() {
public Object run() throws Exception {
DefaultCacheServer.start();
return null;
}
});
}

/**
*/
public static void shutdown() {
DefaultCacheServer.shutdown();
}

/**
* @throws Exception
*/
public static void startDaemon() throws Exception {
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
@Override
public void uncaughtException(Thread t, Throwable e) {
System.err.println("Uncaught exception from Thread " + t.getName());
e.printStackTrace();
System.exit(1);
}
});

Security.runAs(subject, new PrivilegedExceptionAction() {
public Object run() throws Exception {
DefaultCacheServer.startDaemon();
return null;
}
});
}

/**
* @param args
* @throws Exception
*/
public static void startMain(final String[] args) throws Exception {
subject = Security.login("manager", ("password").toCharArray());
Security.runAs(subject,new PrivilegedExceptionAction() {
public Object run() throws Exception {
DefaultCacheServer.main(args);
return null;
}
});
}
}

*********************
Step 7: Use JaasDefaultCacheServer to start the Cache Nodes using the following arguments:

java -server -cp "%COHERENCE_HOME%/lib/coherence.jar:%COHERENCE_HOME%/lib/security/coherence-login.jar" -Dtangosol.coherence.override="C:\Oracle\Coherence\Files\Security\tangosol-coherence-override.xml" -Djava.security.auth.login.config="C:\Oracle\Coherence\Files\Security\coherence-jaas.config" com.sample.JaasDefaultCacheServer


***************************
Let me quickly take you through what happens behind the scene ->

A. When you start the JaasDefaultCacheServer, it will look for the Login Configuration. In the above example, we are using the "com.tangosol.security.KeystoreLogin" that comes with the Coherence product "coherence-login.jar". Whichever Login Module you use, specify in the "coherence-jass.config"

B. During the "login" call Coherence utilizes JAAS that runs on the caller's node to authenticate the caller. This means that,

subject = Security.login("manager", ("password").toCharArray()); will look into the keystore specified in "coherence-jass.config" for authentication. This authentication will provide us with the subject.

C. Once the local authentication is successful, it uses the local Access Controller to determine:

- Determine whether the local caller has sufficient rights to access the protected clustered resource (checkPermission method in MyAccessCotroller);
- Encrypt the outgoing communications regarding the access to the resource with the caller's private credentials retrieved during the authentication phase B above(encrypt method in MyAccessController);
- Decrypt the result of the remote check using the requestor's public credentials (decrypt method in MyAccessController);
- In the case that access is granted verify whether the responder had sufficient rights to do so. (checkPermission method in MyAccessCotroller)

Other Coherence security implementations will be available in future posts.

Thursday, July 28, 2011

Coherence - Security

There are multiple links that provide great example on enabling Security in Coherence:

Secure Oracle Coherence with Kerberos or Active Directory

Coherence Security Examples by Oracle Product Development

Protecting Proxy Servers from Unauthorized Access

I will try to provide step-by-step implementation in future posts covering all the ways in which you can secure Coherence.

Search This Blog