Thursday, July 30, 2009

Building Custom Security Providers with JDeveloper 11g

As I mentioned previously, the WebLogic Server Sample Security Providers have emerged and have found a new home. This is great, but unfortunately the samples are a little out of date. I've received requests for a sample credential mapper, which I hope to be able to post shortly. In the meantime, I thought it would be useful to show how to work with the samples inside of JDeveloper.


Step 1 - Set-up the Application in JDeveloper

Create a new Generic Application in JDeveloper. Create a project for the application and make sure that Java is selected as a project technology. Next, import the samples into the project. Once you've downloaded the samples, unzip it. From JDeveloper, select "Import...Java Source" and then select the src folder from the directory where the samples were downloaded.


Finally, modify the project settings to exclude the "tests" folder. Unfortunately, after some effort there are some parts of this sample that are just "too old" to get working - the test clients, test application, and test domains.

Step 2: Setting up Ant


Add an empty build file to the project, then replace the contents of the empty build file by cutting and pasting the contents of the build.xml from the samples into the build.xml in JDeveloper.
If you've done this right, then you have a project that looks like this in JDeveloper.

The next step, and this is probably the most "complicated" is to modify the build.xml to conform to your specific environment. Everything is keyed off of the lib property. Modify this to value to point to WEBLOGIC_HOME/server/lib - (c:\Oracle\Middleware\wlserver_10.3\server\lib).

The other complicated part is that since you're not running this inside of the WLS environment, the classpath is not their. Instead of dealing with JDeveloper and setting the environment that way, I just added elements to the > elements.


<java classname="weblogic.management.commo.WebLogicMBeanMaker" fork="true" failonerror="true">
<jvmarg line="-Dfiles=${build_dir} -DMDFDIR=${build_dir} -DMJF=${build_dir}/${sampleprovidersjar} -DtargetNameSpace=${namespace} -DpreserveStubs=true -DcreateStubs=true -DmbeantypesDir=${mbeantypes}">
<classpath>
<path location="${lib}\..\..\..\modules\com.bea.core.mbean.maker_1.4.0.0.jar"/>
<path location="${lib}\..\..\..\modules\com.bea.core.utils.full_1.6.0.0.jar"/>
<path location="${lib}\weblogic.jar"/>
<path location="${java.home}\..\lib\tools.jar"/>


The last thing to do is to either make a similar change to the > for the tests or to comment them out or to just ignore the error when running the ant task and the building of the tests fails. For people that are interested in the tests, you should add the following:

<javac srcdir="${test_src_dir}/java" destdir="${class_dir}">

<classpath>
<path location="${lib}\..\..\..\modules\com.bea.core.mbean.maker_1.4.0.0.jar"/>
<path location="${lib}\..\..\..\modules\com.bea.core.utils.full_1.6.0.0.jar"/>
<path location="${lib}\weblogic.jar"/>
<path location="${java.home}\..\lib\tools.jar"/>
</classpath>

</javac>

If you've done everything correctly, you should now be able to build the samples. You do this by running the ant task by right clicking on the build.xml and select the all target.

And...you should have a file called wlSampleSecurityProviders.jar in your WEBLOGIC_HOME\server\lib\mbeantypes directory. This is the jar that contains the sample providers.

Admittedly, this is not a perfect solution. Even if you add weblogic.jar to the project classpath there are some funny things with this set-up. Most notably is the fact that the classes appear to be in the wrong packages. This is because of the way that the samples project is distributed. This can be a but annoying, but I've used this set-up for the WS-SecureConversation work that I did recently, and I found it workable. I'll probably go into more details in a future post, but if people have questions in the meantime, post them here, and I'll do my best to help

Friday, July 24, 2009

Binding WS-SecureConversation Bootstrap Identity to WebLogic Server Identity

In WebLogic Server, when you configure a web service to use WS-SecureConversation, you have a number of choices for how to "bootstrap" the conversation. Besides calling a Security Token Service (STS), you can also send a WS-Trust RequestSecurityToken (RST) message to the endpoint, and receive a SecureConversationToken in return. This token is then typically used to derive keys to sign and encrypt subsequent messages. But, how should the initial exchange where the context is created be secured?

WebLogic Server gives a number of options including 1 and 2 way SSL, Basic Authentication, and UsernameToken. With the exception of 1 way SSL, all of the other policies require the web service consumer to provide an identity. This identity is validated by WebLogic Server in the normal way. The web service can then also have a policy that requires another identity when invoking the service. For example, use 2 way SSL to bootstrap the secure conversation and then SAML to provide identity for the actual service. This makes a lot of sense if you want a separate bootstrap identity, but what if you don't? What if you want to use a single identity to both bootstrap the conversation and identify the consumer? Is there a way to do it without simply sending the same token in both the bootstrap request and the subsequent messages?

This was the question posed to me recently by a customer. There is nothing in the WS-SecureConversation standard that says the bootstrap identity should be preserved, but the requirement does seem pretty reasonable. Also, in discussing this issue with a colleague he made the observation that WS-SecureConversation is like "SSL for Messages". The SSL standard does not require that the original client certificate is passed for identity on every request, but many, if not all implementations do. So, following that analogy, I set off this week to try to get this type of functionality working inside of WLS.

So, after trying what felt like every conceivable approach, and a lot of late nights, this is how you can do it. There are a couple things that you have to know about the bootstrapping process and the WLS web services stack. The first is that during the bootstrapping process a session is created, but that its not associated with the bootstrap user. The second is that the WLS web services client will send the JSESSIONID cookie on subsequent requests. The third is that a HTTP based web service is really two different resources inside of WLS - one of type <url> and one of type <webservices> . The idea is to capture the session, get it associated with Subject created by the authentication of the bootstrap identity, and then push that Subject onto the Servlet stack, making it available for the web-service. As long as the client sends the same JSESSIONID cookie, the bootstrap identity will be preserved.

The solution leverages a SessionEventListener to capture the HttpSession that is created during the bootstrapping process. The session is stored in a ThreadLocal.

public class SessionListener implements HttpSessionListener {
private HttpSession session = null;

public void sessionCreated(HttpSessionEvent event) {
session = event.getSession();
WSCSubjectThreadLocal.getWSCSubjectThreadLocal().set(session);
}

public void sessionDestroyed(HttpSessionEvent httpSessionEvent) {
}
}


With the session stored in the ThreadLocal, the next thing to happen is to capture the bootstrap identity in the form of the Subject, and add it to the session. This can be done through a custom AuthenticationProvider, but this a very unusual provider. Its required, its configured to be the last provider in the realm, and its only purpose is in the commit method to capture the subject.

public boolean commit() {

HttpSession session =
WSCSubjectThreadLocal.getWSCSubjectThreadLocal().get();

if (session!=null) {
session.setAttribute("wsscSubject",this.subject);
WSCSubjectThreadLocal.getWSCSubjectThreadLocal().remove();
}
return true;
}


So, at this point the bootstrapping is complete. The Subject is stored as an attribute in the session and the client is passed the JSESSIONID cookie. Assuming that the client sends the cookie in the next request, all that is left to do is to push the Subject on to the stack. To accomplish this, I used a custom AuthorizationProvider. This provider is only looking for requests, and always returns a PEMIT. Its only purpose if to push the Subject onto the stack.

public Result isAccessAllowed(
Subject subject, Map map, Resource resource,
ContextHandler contextHandler,Direction direction) {

if (resource.getType().equals("")) {

HttpServletRequest request = (HttpServletRequest)contextHandler.getValue("HttpServletRequest");

if (subject.getPrincipals().size()==0) {

HttpSession session = request.getSession();

Subject theWSCSubject = (Subject)session.getAttribute("wsscSubject");

if (theWSCSubject!=null) { ServletAuthentication.runAs(theWSCSubject,request);
}
}
}
return Result.PERMIT;
}


The application needs to be deployed with the Custom Roles and Policies. If the URL is protected in the deployment descriptor, the bootstrapping process will fail - the user is not authorized. Its also worth noting the limitation that the identity is tied to the session and the client is responsible for sending the session in the cookie in the transport. This means that a single client won't be able to maintain two conversations concurrently with the same server. Also, since the identity is not included in the message, this solution is best suited for single party operations - client calls WebLogic Server, and WLS processes the message. Although, since there is a real identity inside of WLS, the identity can be pretty easily propagated using the CredentialMappers (PKI/SAML) of WLS.


Monday, July 20, 2009

ServletAuthenticationFilter - Revisit

I want to clarify what a ServletAuthenticationFilter is used for and when it gets invoked. The explanation in the product documentation is accurate, but I want to add some important context. When the documentation says "the servlet container calls the Servlet Authentication Filters prior to authentication occurring", this begs the question "When does authentication occur?".

Authentication occurs when the resources that the user is accessing is protected. Using the default security model (DD Only), then this is strictly what is defined in the deployment descriptor (web.xml). By default, resources are unprotected. Also, authentication occurs when the current user (including the anonymous user), is not authorized to access a resource.

So, in practice, authentication occurs the first time the user attempts to access a protected resource. ServletAuthenticationFilters enable authentication schemes other than those provided OOTB by JEE like SAML, SPNEGO, OpenId etc. Even though the re-use the standard Filter interface, they are not the same. Standard filters, which are configured on a per-application basis, get called every time, but after authentication and authorization. The fact that ServletAuthenticationFilters get called before is what makes them unique.

Saturday, July 18, 2009

WS-SecureConversation

WebLogic 11g (10.3.1) has support for WS-SecureConversation. What is WS-SecureConversation? According to Wikipedia, not much more than a specification from IBM, MSFT and others. Recently, I've had a couple of customers asking about WS-SecureConversation and how WLS can support it so I wanted to take a little time to discuss what WS-SecureConversation is and explain how to configure WS-SecureConversation on WLS 11g.

WS-SecureConversation enables the creation of a SecurityContext between a web-service producer and consumer. The SecurityContext is essentially a shared key. The SecurityContext is created first, and then the message exchange begins. WS-SecureConversation uses the WS-Trust specification to establish the SecurityContext. One common approach is to use WS-Trust to communicate with a SecurityTokenService (STS). Another is for the consumer and the producer to negotiate the SecurityContext directly. In WebLogic Server, this process is called "bootstrapping". The difference among the policies is just how the two parties establish trust so that they can securely exchange the shared key. Often, the shared key for the security context is used to calculate DerivedKey. Using the concept of DerivedKeys it is common to have one key used for signing the message and another to encrypt the message.

The sample client illustrates how to configure a client application to use WS-SecureConversation. The details on the setting up the server are not obvious, so I'll cover them here.

You'll need a client public/private key-pair and a server public/private key-pair. For demos, I'll just use utils.CertGen and utils.ImportPrivateKey. You'll need both of them in their own java keystore, as well as the certificate in PEM format. Once the SecurityContext is established, messages will be secured with the DerivedKeys, but to establish the SecurityContext, X.509 certificates and either WS-Security or SSL is used to exchange the keys. This is why you need the keys.

In order to configure the server to use DerivedKeys and the SecurityContext, you need to configure a domain level webservice configuration, and set-up the appropriate certificates and credential-providers (DerivedKeys and SecureConversation). This can be very tedious manual process. Fortunately, there is a sample that has a WLST script that does it for you.

WL_HOME\samples\server\examples\src\examples\webservices\wsrm_security\configWss_Service.py

Run the script as follows:

java weblogic.WLST weblogic welcome1 localhost 7001 serverkeystore.jks serverkeystorepass serveralias serverkeypassword

You'll also need to create a CertPath provider, mark it as the default builder, and then configure both the client certificate and server certificates as trusted.

Finally, deploy a web-service protected by the bootstrapping policy, for example:

@Policy(uri = "policy:Wssp1.2-2007-Wssc1.3-Bootstrap-Wss1.1.xml")

This will sign the message with the DerivedKeys. If you want the body encrypted as well, use the following policies:

@Policies(
{@Policy(uri = "policy:Wssp1.2-2007-Wssc1.3-Bootstrap-Wss1.1.xml"),
@Policy(uri = "policy:Wssp1.2-2007-EncryptBody.xml")}
)

You'll need to modify the sample to use your generated stubs. Make sure that you use JAX-RPC web-service stub.

This is probably the first of a few posts of WS-SecureConversation. I'll definitely need to cover the topics of WS-SecureConversation and WS-Trust, WS-SecureConversation and WS-ReliableMessaging. If there are more topics of interest, let me know.

Friday, July 17, 2009

Oracle Open World 2009 - Identity Management Sessions

The list of sessions for Oracle OpenWorld 2009 is available.

I'll be presenting on Oracle Web Services Manager (OWSM) and securing FMW 11g. I was talking to Vikas last night (driving back from NJ) and the current thinking for the presentation/demo is:

MSFT .net client using Kerberos Token Profile invokes a BPEL process which in turn invokes JAX-WS WebService running on SOA Suite 11g. We'll probably use SAML (Sender vouches?) to get end-to-end identity propagation from BPEL to the final service.

I'm definately open for input/suggestions for what people would want to see. Also, I'm exceited about the opportunity to present as I'll get to continue to come-up to speed on OWSM 11g. Obviously, this will be a source for numerous postings here.

Stay tuned

Tuesday, July 14, 2009

SOA Perspective on Authorization

I'm blogging in two places, and some times I'm not sure which makes the most sense. Thanks to modern search technology, maybe it doesn't matter :)

I just finished a post on Authorization Pre-Caching. To avoid accusations of a "Remember When" cheesy sitcom, re-tread post, I'll add some more color on this use case in the broader context of SOA, and specifically OSB.

If you want to have a centralized authorization solution and it needs to be very very fast, SOAP is not a good choice. In my experience you're adding 10s of ms latency compared to a binary protocol like RMI. For general purpose services this may not matter, but for fast authorization/entitlement services this is a non starter. If you have to have a very fast binary protocol, consider building a custom transport.

This enables the very fast compact protocol that is required to meet extreme performance requirements, but instead of a proprietary or light-weight contained, it can be serviced by an enterprise class container that provides routing, SLA, reporting (insert OSB marketing here)

If said modern search technology brought you here, and you found a post on exposing security functionality with SOA, but you really wanted "How to Secure my SOA", try here - from last year's OOW

Thursday, July 9, 2009

OPSS Sample Application


Over the past few weeks, I'd been working with the development team on putting together a nice OPSS Sample Application

The README gives a lot of detail about what the application does and how to use it, so I wanted to spend a little time here to point out some of the ways that existing WLS secured applications can be enhanced with OPSS and also some of the finer points on the application itself.

OPSS provides some good simple user profile services. Admittedly not as elaborate as something like an OIM would provide, but probably cleaner and easier to implement then going through the MBeanReader interfaces of WLS. Also, unlike the MBean interfaces in WLS, there is more than just users and groups. There's user and group attributes. In the sample application this is all very nicely wired to the embedded LDAP that ships with WLS, but through simple configuration can be changed to work with an enterprise repository (LDAP).

If you look at the initialize method of the LdapIdStore class inside of the LdapDC project, you see the set-up of the JPSContextFactory, JPSContext, and IdentityStore instances. The IdentityStore is essentially a handle the the AuthenticationProvider configured in WLS. In the same project, you'll also find the LdapIdStoreView class. This class demonstrates how to get a handle to the UserManager and RoleManager classes. These classes give you access to the users and enterprise roles defined in the application. The FMW Security Guide has all of the details

In the sample application, there are three enterprise roles - basic user, premium user and ezshareadmin. Notice that the sample application also comes pre-configured with a list of users assigned to those roles. This was all done from JDeveloper and packages as part of the application. When the application is deployed, the information is published into WebLogic Server's authentication provider - the embedded LDAP. For building applications, this can simplify and speed testing. All of the user, group, policy information etc. is stored in the jazn-data.xml, and as I mentioned can be edited from inside of JDeveloper.


In general, I'm not a huge fan of the Java 2 security model, but I think that the way that the CredentialStoreFramework (CSF) uses it in this example is reasonable. Basically, all of the encryption/decryption of the files is done with a symmetric key. Any code that can gain access to that key can access the messages. By using Java 2 permissions model, and having to explicitly grant code access to the key, this restricts the access to only authorized code. This is very useful in centralized environments where many applications are hosted in a single server. In the sample application all of the code is granted access for simplicity, but could be further restricted depending on requirements. This model also breaks the cycle of having to have the password to something...for example, keys are stored in a Java Keystore require a cleartext password to get the private key, but then where do you store that password? Prompt for it at start-up? Java 2 security provides the answer.

I also like the way that the sample application implements accessing the credential store. All of the access is centralized through two methods in the CryptoUtil class. This class can be found in the ezShareModel project. The key thing is that it uses PriviledgedAction to access the store.


This greatly simplifies the configuration of the Java 2 permissions since only the CryptoUtil.class has to be granted access, regardless of whatever other code is in the call stack.

I personally think the coolest part of the sample application is the way that the encryption and decryption is integrated into the ADF View Object. I'm constantly getting questions about data security - mostly around authorization - but this is another key requirement - confidentiality of data on disk. This can be achieved using features of the database, but what this solution shows is a clever way to do it from the middleware. If you look at the BasicFilesView.xml and BasicFilesViewRowImpl.java also in the ezShareModel project, you'll see that the view is using a custom row implementation, and that implementation in-turn is using the CryptoUtil class for all of its encryption/decryption. Very nice!

People can definitely post their questions here about the sample application or maybe suggest some use cases for extending the application....maybe Web Services security...interesting SSO or authorization scenarios. Let me know.

Wednesday, July 1, 2009

OpenId SSO for WebLogic Server

With the launch of 11gR, there is a new way to share code samples within the Oracle community. Check out samplecode.oracle.com

To that end, I thought I'd make my community contribution in the form of an
IdentityAsserter that provides SSO to WLS using OpenId

There were a couple of reasons to do this, but the main one was to build a reasonable example of the ServletAuthenticationFilter. WLS uses it internally for the SPNEGO support, and SAML SSO support, but I'd never really had a need from a customer to use it until recently. The need here was OpenId. On the OpenId side, I used the OpenId4Java. If people look at the sample, I'm sure there is a lot more that can be done, and I've only done very cursory testing with the Personal Information Portal at Verisign Labs. Again, this is not exactly my focus, so apologies in advance for any issues there.

So, what is the ServletAuthenticationFilter? Well its really just a special type of IdentityAsserter. It's an IdentityAsserter that adds a Filter to every web application inside of WLS. The filter only gets called when the user is accessing a protected resource, but before regular authentication kicks-in. The key is that this happens before authentication. This allows the filter implementation to go do something, like challenge the user for a different type of credentials other than what WLS supports natively. Also, the ServletAuthenticationFilter has the notion of multi-part challenges, like those that are required to do SPNEGO or OpenId. There is an initial step, and then multiple continue steps, until the challenge is completed. There are a bunch of different interfaces, and it can be a little confusing, but here's my best explanation:

The Filter logic:
1. Is there an existing challenge context - normally stored in the HttpSession.
a. If there is, call continueChallengeIdentity
b. If there isn't, call assertChallengeIdentity
2. Check if the challengeContext.hasChallengeContextCompleted
a. If it has, get the Subject and call ServletAuthentication.runAs(subject,request) - this pushes the subject onto the WLS Stack
b. If it hasn't, get the ChallengeToken. Process the token, and return it to the user.

The Identity Asserter Logic:
1. Build the Basic Identity Asserter First - this is just the plain old IA that sets up a CallbackHandler. This is based on the token type that you're going to extract. In my example, I just extended the SimpleSampleIdentityAsserter, so really my tokens are just usernames.
2. Implementing the ServletAuthenticationFilter interface
a. All that this really does is just instantiate the filter...very simple.
3. Implementinf the ChallengeIdentityAsserterV2 interface
a. The assertChallengeIdentity is going to get called when the filter calls the AppChallengeContext.assertChallengeIdentity, so this is the intial call. In this method, you'll need to instantiate your implementation of the ProviderChallengeContext, and return it.
b. The continueChallengeIdentity method gets called when the filter calls AppChallengeContext.continueChallengeIdentity. This time you get passed the ProviderChallengeContext that you created in the assertChallengeContext.
c. When you finally have a valid user, you need to set the CallbackHandler on the ProviderChallengeContext. This is simple, since you're already inside of an IdentityAsserter. Basically, just call assertIdentity, get the CallbackHandler, mark the ProviderChallengeContext has completed and you're done.

So, by looking at the Filter and IdentityAsserter implementations, we can start to understand what the purposes of some of the other objects in the model. The ProviderChallengeContext is used to hold the start of the challenge. Its typically stored in the user's session, so you can just use instance variables inside of it to hold the state. One more thing about the sessions. The filters are instatiated just like other regular filters, which means that they are scoped to applications - configured globally, but all running inside of the application. The sessions that you get from the HttpServletRequest are tied to that application. If you want to pass information between apps, you'll need to do it on the URL.

The other implication, is that the methods on the IdentityAsserter take a ContextHandler, but the methods of the AppChallengeContext take an AppContext. Basically, under the covers the AppContext is wrapped/converted into a ContextHandler. This probably means that you'll need to build you own implementation of the AppContext to hold your data. This included the HttpServletRequest and HttpServletResponse objects.

That's basically it. The rest of the information is readily available in the product documentation. I encourage people to download and try the sample. As always, comments welcome.