ptg 232 Chapter 9 Security Model Listing 9.15 Application Code to Call a Secured Service def callDataService( args ) { logger.INFO {"Starting with: ${args}"} def URL = "https://crownjewels.acme.com/resources/${args.service}" if ( args.id ) { URL += "/${args.id} } args.remove('service') args.remove('id') args.eachWithIndex() { it, idx -> URL += (idx == 0 ? '?' : '&' ) + URLEncoder.encode(it.key, "UTF-8") + "=" + URLEncoder.encode(it.value, "UTF-8") } logger.INFO {"URL: ${URL}"} def response = Connection.doGET(URL) def doc = new XmlParser().parse( response.responseBody ) logger.INFO {"Results : ${doc}"} return doc } In this example, we make a dynamic call to some service as defined by the method parame- ters, and receive an XML document as a response. It is a big assumption that we will be receiving an XML response, but this serves for this example. If you are expecting a response other than XML, adjust the response handler to process the correct data type. Let’s examine this bit of reusable code a little more. In the first several lines, we build up the base URL. The static part of that URL should really be defined as an entry in the application config file, and not a static string as shown in this example. We supply the actual service to be called in the args.service entry, and if supplied, we add on the resource ID. Next, we remove the service and ID entries from the argument map, and then walk the remain- ing args and append them to the URL as parameters. Encoding the parameters is necessary because the parameters might include characters that are not transmittable in their original encoding. Finally, we open a GET connection to the URL and pull in the results as an XML docu- ment. There is a lot more we could do to improve this method, such as dynamically handling dif- ferent response data formats, but at least you should be able to see how easy it is to make secure connection calls to remote services. Download from www.wowebook.com ptg OpenID Configuration 233 Conclusion In this chapter, we have taken a whirlwind tour of various security subsystems within the Web- Sphere sMash environment. There is a lot we didn’t cover about various configuration options within each security scenario. The documentation provided on the Project Zero website goes deeper into the security details. The goal of this chapter was to give you the basics needed to cre- ate a secure WebSphere sMash application. The information learned in this chapter is directly usable in real-world applications. Download from www.wowebook.com ptg This page intentionally left blank Download from www.wowebook.com ptg 235 In this chapter, we discuss a variety of WebSphere sMash capabilities and provide an insight as to when you can use these features to add greater flexibility to your application. For instance, there are often times when an application cannot simply rely on the standard request/response cycle dictated by the user’s browser. You may want to perform some preparation work upon application initialization and not force the first user in to bear the brunt of the extra processing delay. There may be times where you want your application to periodically check in with another server, pull in news feeds, or send usage statistics to a monitoring site. The scenarios are limitless and may not fall within the normal traffic patterns of your users. WebSphere sMash provides several features to assist you in processing data based on vari- ous events. These events can be regular and cyclical in nature, where a timer can initiate an event, or you may need to watch a file system for changes and process those files. There are also facili- ties for watching POP mail accounts for new mail, and queues can receive asynchronous mes- sages as part of the Reliable Transport Extension (RTE). A large network of connected applications can also use WebSphere sMash to communicate without any users or browsers being involved in the mix. This opens the door to a wide array of internetworked applications that can stay in contact with each other. Timers A timer is used to fire re-occurring events. The timer ticks at predetermined intervals, and a han- dler event method called onTimer() can then take any required actions. To use timers, you need to add the zero.timer dependency to the application’s ivy.xml file. Then, for each process you want to execute, add a timer task entry and event handler into the zero.config file. By convention, you should place your timer handler scripts into a directory C H A P T E R 10 Event Processing Download from www.wowebook.com ptg 236 Chapter 10 Event Processing called /app/scripts/timers. This is just a recommendation; you can organize your code as you see fit. In the configuration snippet shown in Listing 10.1, we define a timer named “heartbeat,” which fires every 30 seconds, and call the onTimer method of the /app/scripts/timers/ heart- beat.groovy file. In the first line, we define the timer task. A timer task is an object that has a single property called a “delay,” or the tick time in seconds. When the task ticks, it fires a “timer” event, and sets the event task name to the ending name of the timer task, which in our sample is “heartbeat.” For every timer task, there is a corresponding handler block. The handler block con- sists of an events type of timer, with conditions matching the event’s task name to the timer’s task name. The handler determines the script to call for the doTimer method. The instanceData member contains a map of arguments that are passed into the onTimer method. Listing 10.1 Timer Configuration /config/timer/tasks/heartbeat = { "delay" : 30 }/config/handlers += [{ "events" : "timer", "conditions" : "/event/_taskName =~ heartbeat", "handler" : "timers/heartbeat.groovy", "instanceData" : { "myArg1" : "someConfigurableValue" } }] So, what do we put into our doTimer method? Well, that can basically be whatever you want. The instanceData variables are accessible from the “event” global context. So, in our sample configuration, the doTimer method can grab the instance data using zget(“/event/myArg1”). Listing 10.2 shows our handler code located in the file: /app/scripts/timers/heartbeat.groovy. Listing 10.2 /app/config/timers/heartbeat.groovy package timers def onTimer() { logger.INFO{"Heartbeat timer fired"} logger.INFO{"Event name: " + zget("/event/_taskName")} logger.INFO{"Event Instance Data MyArg1 : " + zget("/event/myArg1") } } Start the application, and let’s see what we get produced to the console. Nothing. Hmm, even waiting 30 seconds, and we get nothing. The reason for this is that the timer is not fired until a request comes into the ZSO, which then actually starts up the application. So, use your Download from www.wowebook.com ptg Application Initialization Using Timers 237 browser to access the application (http://localhost:8080). The browser displays the normal sMash “up and running” page, whereas the console log shows our logging output. We can take away a few things from this test. First, timers by default start only when the ZSO has activated the appli- cation, and by consequence, they also stop firing when the ZSO idles the application. We’ll address this seemingly erratic behavior momentarily. The other thing to notice on this little sample is that a timer event fires immediately when the application is initialized, and then upon each tick’s delay value. This can be used to our advantage for using a timer to perform a one-time application initialization. By default, the timer will not start until the first request comes in and the ZSO initiates the application. If you need the timer to start as soon as the application initializes, set the following in the zero.config; the timer fires immediately and then at the defined intervals: /config/zso/immediateStart=true By default, the ZSO starts an application when a request comes in on one of the listening ports. At this point, ZSO starts the application and subsequently the timer service. After a period of inactivity, ZSO closes down the application and therefore the timers that are running within that application. If you set the ZSO immediateStart flag, ZSO immediately starts the applica- tion and allows the timer to fire. Depending on the delay time of the timer, the ZSO may still shut down the application, but the timer(s) continues to fire at the appropriate intervals, forcing the ZSO to bring the application back up into listening mode. Application Initialization Using Timers One common use of a timer is to perform a one-time application initialization. As stated earlier, a timer is fired immediately upon application startup and then at each delay interval. So, to force an application to perform a single startup, set the delay time to a very large value. It will fire one time, and remain dormant thereafter. The only issue to resolve is to ensure that initialization has completed before any user requests are processed. When the application is run under the ZSO, this race condition is even more likely. The solution is to use an initialization flag. When a request comes into the ZSO for an application, the ZSO starts up the application, which immediately fires the timer event. The timer event and the servicing of the request happen in parallel, which means that each entry point or starting page of the application needs to check for initialization before continuing and actually servicing the request. Let’s go through a quick example of using an initialization flag. First, create a new init timer, with a delay time of 9999999 (or any ridiculously large value) and an event handler stanza, as shown in Listing 10.3. A value this large (~3 years) will ensure that our timer never fires again. This is essentially the same as our first example, but this time, we are not defining any instanceData values. Download from www.wowebook.com ptg 238 Chapter 10 Event Processing Listing 10.3 Initialization Timer Configuration /config/timer/tasks/init = { "delay" : 99999999 } /config/handlers += [{ "events" : "timer", "conditions" : "/event/_taskName =~ init", "handler" : "timers/init.groovy" } The /app/scripts/timers/init.groovy::onTimer method shown in Listing 10.4 performs whatever initialization processes our application requires. In this sample, we just put the thread to sleep for several seconds to simulate some rather long database activity. After the initial- ization has completed, we set an application-level context flag to indicate that we are fully initial- ized and ready to accept incoming requests. This is all well and good, but what if a request comes in before our flag is set? We need to create a blocking method that holds the request(s) until the appli- cation is initialized. This is represented in the ”waitForInitialized” method. This method simply enters a time-delayed loop waiting for the proper initialization flag to be set. Although it is probably not a great practice to sleep your request threads, it can come in handy in this situation. Listing 10.4 /app/scripts/timers/init.groovy package timers def onTimer() { try { if ( ! zget("/app/initialized") ) { logger.INFO{ "Initializing application - " + "from timer task (${event._taskName[]})" } Thread.currentThread().sleep(30000) // 30 sec. zput( "/app/initialized", true ) logger.INFO{ "Initialization completed." } } } catch ( e ) { logger.SEVERE{ "Initializing error - ${e}" } } } def waitForInitialized() { def x = 0 while ( ! app.initialized[] ) { logger.INFO{ "Waiting for initialization to complete ${++x}" } Download from www.wowebook.com ptg Kickers 239 Thread.currentThread().sleep(1000) // 1 sec. } return true } The only thing we have left to do is to add the call to our waitFor method in each pos- sible web page of the application. We show a sample of this in Listing 10.5, showing us a simple index.gt file. Although this sort of waiting for initialization process becomes cumbersome to manage if there are many potential entry pages into your application, it does solve a rather thorny issue. Listing 10.5 /public/index.gt <% invokeMethod("timers/init.groovy", "waitForInitialized", null ) %> <html> <head> <title>Init Test</title> </head> <body> <h1>Hello!</h1> </body> </html> Test out our initialization process by starting the application and quickly attempting to access the main page. The browser should be forced to wait several seconds before the ready flag is set and the rendering is permitted to continue. Check the log file to verify that the proper sequence of events has taken place. There are other ways that you can explore to gain both a functional application initializa- tion and still maintain the benefits of using ZSO to manage overall application resources. One entails having a dedicated “timer” application that is always running and firing events. This assumes that the initialization is for more generic resources, such as databases, file systems, or other remote resources. The timer application can also “kick” other applications and delivery information at regular intervals. We discuss kickers in the next section. If you have a cluster of related applications on a single host, organizing timed events around a single long-running “timer” application can solve a lot of issues with the individual applications running cyclical events, while still allowing the ZSO to manage the other application instances. Kickers There are several different styles of kickers that we cover in this chapter. The purpose of a kicker is to “kick” or notify a remote application that an event has occurred. This kick is done via a POST connection. The connection is automatically retried as necessary until a successful POST Download from www.wowebook.com ptg 240 Chapter 10 Event Processing Table 10.1 Common Kicker InstanceData Members InstanceData Configuration Members Description receiverURL The target URL to receive the “kick” notification. This is a required variable for all kickers. Despite its name, you may also use a connection name instead of an actual URL for this field. maxRetries The number of times to attempt to kick the remote application. The default is five retries. maxDelay This is the delay time between failed kick attempts. The default is 5 seconds between retries. config You ca n s up ply c us to m C onn ec tio ns varia bl es us ing t he co nfi g map. This is typically used to supply the username and password under basic authentication connections. This is an options setting based on your requirements. has been made, or the number of configured retries has been exceeded. Kickers use the timer sub- system discussed previously to perform a kick, or test for conditions that will invoke a kick action. The kick call returns either success or failure based on the status code returned from the POST call to the remote application. To enable kicker support in your application, you need to add the appropriate zero.kicker module into the ivy.config. There are a few new instanceData variables that go into the event stanza for each type of kicker, which we need to define in the configuration file. Other kicker types also have their own instanceData variables, which we’ll point out shortly. The variables that are shared among all kickers are shown in Table 10.1. We’ll look at sample configurations for each kicker. As a matter of consistency and convention, it is recommended that you place all kicker han- dlers under the ”/app/scripts/kickers”. Of course, you are free to place them wherever makes sense to you and your application structure. Simple Kicker The most basic kicker simply calls a handler on each timer tick, passing in the variables defined in the instanceData block from the configuration file. It’s simply a matter of calling the kick function from your custom handler. This will perform a POST to the designated receiverUrl, passing in a map of the parameters passed into the kick method. Let’s build a simple kicker to illustrate this concept and look at what the receiving applica- tion delivered. First, add the ”zero.kicker” module to the ivy.config file. Next, create a timer Download from www.wowebook.com ptg Simple Kicker 241 and event stanza in your application’s configuration file, as shown in Listing 10.6. Remember that timers will not fire when the application is idled by the ZSO, so make sure you set the immediateStart flag to true. Listing 10.6 Simple Kicker Configuration /config/zso/immediateStart=true /config/timer/tasks/myKicker = { "delay" : 120 } /config/handlers += [{ "events" : "timer", "conditions" : "/event/_taskName =~ myKicker", "handler" : "kickers/mySimpleKicker.groovy", "instanceData" : { "receiverUrl": "http://localhost:8080/resources/kickReceiver" } }] We create a standard timer with a two-minute tick delay, and a corresponding handler that calls ”mySimpleKicker.groovy”, which is shown in Listing 10.7. Notice how we define the receiverUrl. Under normal circumstances, this would point to a different application, likely residing on a different host. For this sample, we’ll just call a resource in the same application. Listing 10.7 /app/scripts/kickers/mySimpleKicker.groovy import zero.kicker.Kicker def onTimer() { def args = [ "arg1": "Test message", "number1" : "234" ] logger.INFO{ System.currentTimeMillis() + ": mySimpleKicker: sending: " + args } def kickOk = Kicker.kick( args ); logger.INFO{ System.currentTimeMillis() + ": mySimpleKicker: kickOk: " + kickOk } } There is actually a lot to inspect in this little bit of code. First, we import our Kicker class, which contains several variations of the kick() method. This simplest and most common class accepts a map of arguments to be sent to the remote host. The URL is automatically retrieved Download from www.wowebook.com . needed to cre- ate a secure WebSphere sMash application. The information learned in this chapter is directly usable in real-world applications. Download from www.wowebook.com ptg This page intentionally. args.remove('service') args.remove('id') args.eachWithIndex() { it, idx -& gt; URL += (idx == 0 ? '?' : '&' ) + URLEncoder.encode(it.key, "UTF-8"). to perform a one-time application initialization. As stated earlier, a timer is fired immediately upon application startup and then at each delay interval. So, to force an application to perform