The company I work for is deploying a Single Sign-On solution between its major JEE applications using CA Site Minder. All these JEE applications uses the standard JEE authentication and authorization (JAAS), which is managed by the application server. The overall reference architecture is to install SiteMinder Application Server Agent (ASA) on WebLogic Server’s machine (it will make available some new SM Security Providers to configure into the WLS security realm) and install SiteMinder Web Server Agent (WSA) on Web Server’s machine (Oracle HTTP Server in our case).
With this SSO solution, the authentication flow we achieve is:
- User requests for a protected page;
- SiteMinder agents redirects to an single unified login page, propagating the context of the original request;
- User enter his credentials on the unified login page;
- The unified login page authenticates the user against SiteMinder directories and redirects to the original page;
- User sees the protected page (with his valid “UserPrincipal” in the security context).
During this development, one of the major issues we faced was setting up the developers machines to make them able to integrate with SiteMinder in their local environments, because SiteMinder solution requires a lot of settings to enable each developer’s local WLS to connect to it, such as a full functional SM installation for which each developer need connectivity and countless settings on SM’s administration console for each developer machine, in addition to many other issues, like for example, if developer’s IP changes, then more configuration is needed… if SM is offline, then developer’s WLS not even starts… both SM and developer must have connectivity to the unified login page, and the token cookie (SMSESSION) must be set on the same domain that the developer’s local application runs, and many other issues. It goes on to become impractical as we talk about large or distributed development teams.
To solve this problem, I made a “Site Minder WebLogic Security Provider Mock” solution, which consists in a set of standard Java binaries that emulates the SiteMinder Application Server Agent behavior plus SiteMinder Web Server Agent behavior. This solution permits that developers can simulate a real SiteMinder SSO behavior in their local environments without need to any external dependencies, not even the SiteMinder. Depending on the mock configuration, it is flexible to emulate only the ASA behavior, only the WSA behavior, or ASA plus WSA behavior.
This solution consists of the following components:
- SM Identity Asserter Mock – it’s a custom WebLogic security provider which listens for a “dummy” SMSESSION cookie and simulates the SM Application Server Agent behavior;
- SM Login Page Mock – it’s a simple login page which authenticates against the container and creates the “dummy” SMSESSION cookie
- SM Web Agent Filter Mock – it’s a servlet filter which simulates the front SM Web Server Agent behavior;
- Configuration File – it’s a properties file containing the mock parameters, which will be detailed later;
- SM Example App 1 – it’s a simple web application with a protected page, just to test the SSO;
- SM Example App 2 – it’s another web application identical to the above, just to test SSO between them.
Edit 02/06/2015 – New version available: 1.1
You can download the full SiteMinder WebLogic Security Provider Mock components here (click over zip file then “Raw” button).
Installing the SM Identity Asserter Mock
1 – Copy the mock agent lib “SMIdentityAsserterMock.jar” to the following folder:
2 – Restart the WebLogic server.
3 – Copy the configuration file “SMSecurityProviderMock-config.properties” to some folder accessible to WebLogic. In this example we used the above:
|cookieName||Cookie name for the SSO; to SiteMinder it must be “SMSESSION”|
|cookieDomain||Cookie domain for SMSESSION; to make tests on localhost, this value must be empty|
|cookiePath||Cookie path for SMSESSION; must be set to “/” because the cookie must be sent to every application in SSO|
|cookieMaxAge||Time to live for SMSESSION cookie at client side; use “-1” to indicate that the cookie will persist until browser shutdown|
|loginPageUrl||The mock login page URL; assuming that you are using the default port and context path, it will be “http://localhost:7001/SMLoginPageMock”|
|tokenExpirationInSecs||Time in seconds in which the mock agents will consider that SMSESSION token has expired|
|wsaEnabled||Boolean flag to enable or disable the WSA Filter Mock, useful if you don’t want to change the applications “web.xml” between environments|
4 – Open the WLS administration console, and add a new security provider of type “SMIdentityAsserterMock”:
5 – Click on “Reorder” and make sure that the new provider will be the first of the list:
6 – Click on the “SMIdentityAsserterMock” provider on the list and go to tab “Provider Specific”. Configure the values according to following table:
|Protected Domains||List of application contexts that will participate in the SSO. The mock agent will ignore any other context even if SMSESSION cookie is present. It’s similar to the “Domain” concept of SiteMinder.|
|Config File||Full path on filesystem where the “SMSecurityProviderMock-config.properties” file is present.|
7 – Save your settings and restart WebLogic so changes can take effect:
Installing SM Login Page Mock and Sample Apps
1 – Open the “SMLoginPageMock.war” compressed file with some zip editor and modify the contents of “web.xml”, changing the “configFile” context parameter to point to the full path of the config file on filesystem, like show below:
2 – Save changes and deploy “SMLoginPageMock.war” to the WebLogic Server (follow the default deploy process).
3 – Open the “SMExampleApp1.war” compressed file with some zip editor to see the contents of “web.xml”. You will notice that we have a servlet filter called “SMWebAgentFilterMock”. This is what you should do in your web application to enable the WSA mock behavior on top of the ASA. If you don’t use this filter, then your SSO will behave like you have only the ASA:
Obs.: to use this filter you have also to put the dependencies in your “WEB-INF/lib”, which are the “SMWebAgentFilterMock-1.0.0.jar” and “commons-codec-1.8.jar”.
To the filter work properly, it also must be the “VERY FIRST” filter in you app filter chain, so it must be the first filter declaration in “web.xml” file. It also must be mapped to intercept all resources “/*”, and only “REQUEST” dispatch mode, to act precisely like a web server layer in front of all application requests.
You must also configure the “configFile” (the same as did previously) and “secureResources”. The secureResources must contain a list of comma-separated-values, containing all the url patterns for all protected resources inside the security constraints, it’s similar to the “Realm” concept on SiteMinder. Unfortunately the filter can’t read this values directly from the security constraints, so it must be declared again (like in a realm SiteMinder Realm configuration):
4 – Save changes and deploy “SMExampleApp1.war” to the WebLogic Server (follow the default deploy process). Do the same thing for “SMExampleApp2.war”.
Testing the Single Sign-On
1 – Create some test user on WebLogic default security realm:
2 – Open a browser and go to “SMExampleApp1” application:
3 – Try to access the protected page. The first request to a protected resource without authenticated session will be intercepted by the authentication filter component inside the ASA mock, which will redirect to the login page:
4 – Type the test user login and password, and submit the login. Now you must be redirected to the original protected page, with the security context filled with the UserPrincipal, like shown below:
Some interesting things to note in the picture above:
- Login page created SMSESSION “mock” cookie;
- Identity asserter mock interpreted SMSESSION “mock” and recognized the user, making the WebLogic to fulfill the JAAS Security Principal;
- Web agent filter mock recycled SMSESSION, extracted information from it and injected SM_USER and SM_SERVERSESSIONID into HTTP request headers to be available to the next layer (like a real WSA would have done).
5 – Go back to index, the click on the link to go to “SMExampleApp2”. Notice that now the UserPrincipal is fulfilled in application 2 also (and the JSESSIONIDs are intentionally different for each application), so we accomplished the Single Sign-On as expected:
6 – Go to protected page on app 2, just to see the access granted:
7 – As a last test you can force delete the SMSESSION cookie from your browser session or wait until its expiration, and the expected result is the login page being shown again for a protected resource access attempt.
Your solution must provide a “Single Sign-Off” page also. This can be easily accomplished by some servlet which removes the SMSESSION cookie from the client. But remember that only doing this is may not be sufficient, because the user principal can remain stuck into the specific applications Web Session (JSESSIONID). So, each of the applications participating on the SSO must implement some logic into a filter which compares this two cookie states and then invalidates the session whenever necessary (e.g. check the presence of SMSESSION and compare the current user principal against the SM_USER header).
The login page mock provides a simple logout URL, which erases the SMSESSION and redirects to a custom origin URL:
Obs.: notice that SMSESSION is gone, but the user principal still stuck into Web Session JSESSIONID, so your application must prevent this situation and handle accordingly.
Overall SiteMinder Agents Single Sign-On Behavior
The purpose of this post was present the SiteMinder WebLogic agents mock solution designed by me to help developers to develop and integrate, but by experience we notice some exotic behavior on the SiteMinder agents in general. Perhaps in a next article I can drill down in the detailed behavior of each agent and present some tips to implement a SSO solution in SiteMinder which gracefully handles these various scenarios, when or not to use each agent ASA and/or WSA, but the table below provides a good overview of the ASA and WSA behavior when used isolated or together:
Web Application Context
|SiteMinder Application Server Agent Behavior||SiteMinder Web Server Agent Behavior|
|Accessed Resource||JSESSION_ID||SMSESSION||Expected Behavior||JAAS Security Principal||
|Public||None or Not Authenticated||None||Grant acess||No||None|
|Public||None or Not Authenticated||Valid||Grant acess||Yes||Recycle SMSESSION and add SM HTTP Headers (like SM_USER and SM_SERVERSESSIONID)|
|Public||None or Not Authenticated||Invalid or Expired||Grant acess||No||Set SMSESSION = LOGGEDOFF|
|Public||Authenticated||Valid||Grant acess||Yes||Recycle SMSESSION and add SM HTTP Headers (like SM_USER and SM_SERVERSESSIONID)|
|Public||Authenticated||Invalid or Expired||Grant acess||Yes||Set SMSESSION = LOGGEDOFF|
|Protected||None or Not Authenticated||None||Redirect to login page (by ASA)||No||Redirect to login page (by WSA). Obs.: using the SMWebAgentFilterMock, the first redirect will still be made by ASA and only the subsequent by the filter (due to JEE architecture restriction), but the result is the same.|
|Protected||None or Not Authenticated||Valid||Grant acess||Yes||Recycle SMSESSION and add SM HTTP Headers (like SM_USER and SM_SERVERSESSIONID)|
|Protected||None or Not Authenticated||Invalid or Expired||Deny access with HTTP 403 error||No||Set SMSESSION = LOGGEDOFF and redirect to login page (by WSA)|
|Protected||Authenticated||None||Grant acess||Yes||Redirect to login page (by WSA)|
|Protected||Authenticated||Valid||Grant acess||Yes||Recycle SMSESSION and add SM HTTP Headers (like SM_USER and SM_SERVERSESSIONID)|
|Protected||Authenticated||Invalid or Expired||Grant acess||Yes||Set SMSESSION = LOGGEDOFF and redirect to login page (by WSA)|