×
[searchandfilter taxonomies="search"]

Version Control for PeopleSoft demo

By Chris Heller • March 10, 2009

 

In the past few weeks, we’ve had a lot of interest in our new Version Control for PeopleSoft product. For those interested in learning more about it, here’s a link to the product pages (with a full demo embedded into the “Demonstration” tab).

If you aren’t using anything for Version Control for your PeopleSoft objects, you’ll definitely want to check it out (and share it with others in your organization).

Feel free to contact us at Info@GreySparling.com if you are interested in trying this product out.

Labels:

Put the Appsian Security Platform to the Test

Schedule Your Demonstration and see how the Appsian Security Platform can be tailored to your organization’s unique objectives

Grey Sparling "PeopleSoft Experts" Webinar Series

By Chris Heller • February 20, 2009

 

This blog post falls under the category of why haven’t we done this earlier?

Over the almost 4 years that we’ve been in business, we’ve had lots of folks who have read our blog and attended our “tips and techniques” user group sessions ask us to make this information available to others in their organization who aren’t able to travel to physical meetings. Throughout the month of February, we’ve been piloting webinars to a select group of people to get out the kinks and so far, the feedback has been extremely positive (and the response rate we’ve received has exceeded even our most grandiose expectations).

Therefore, we are launching our webinar series, which is a combination of general tips and techniques sessions as well as deep dives into our products.

Upcoming Webinars

We have 3 new webinars that we’re opening up for registration immediately

Development Best Practices for PeopleSoft Enterprise

    Wednesday, March 4 @ 12:00pm PST. Click here to register.

    Learn from the PeopleSoft experts the best techniques for developing in your PeopleSoft environment. We will discuss the common types of modifications made to PeopleSoft applications, and the best means for making changes with minimal impact and cost to your PeopleSoft environment, while still leveraging the functionality available in PeopleTools. We will also discuss techniques for analyzing impact and managing the changes you may be making.

Getting Started with PeopleSoft Reporting

    Wednesday, March 11 @ 12:00pm PST. Click here to register.

    You need to write a report, but how should you go about building it? Out-of-the-box, you are provided with several tools to write reports, an application with thousands of tables, trees, effective dating, and multi-language translations. Perhaps your organization has even standardized on a 3rd party reporting tool. This session will teach you best practices and techniques for determining what tool to use, and how to go about building, securing, and deploying reports against your PeopleSoft application.

Operational Excellence with Grey Sparling Version Control for PeopleSoft

    Friday, February 27 @ 12:00pm PST. Click here to register.

    If you would like to have better control over your development and release processes for your PeopleSoft environments, you will want to attend this session. We will be providing an overview of best practices in managing your PeopleSoft development and releases as well as our product offerings in this space.

 

We will be scheduling future webinars for other topics, so stay tuned.

Labels:

Put the Appsian Security Platform to the Test

Schedule Your Demonstration and see how the Appsian Security Platform can be tailored to your organization’s unique objectives

Out of Available Memory error running Application Engine

By Chris Heller • February 15, 2009

When you run an Application Engine program from within Application Designer (as we mentioned in our blog post on Application Engine Development Tips) and turn on the checkbox for sending output to a log file, it always defaults to sending the output to c:temp.

If you don’t have a c:temp directory though, you’ll end up getting the “Out of Available Memory” error message.

This problem doesn’t occur when running Application Engine via the process scheduler because the process scheduler has already arranged the output directories appropriately (so that each process instance’s output can be tied to the instance number).

It should default the output directory to %TEMP% and just expand that at runtime, but until it does, then the best thing to is just create a c:temp directory so that you don’t have to keep changing it all the time.

Labels: , ,

Put the Appsian Security Platform to the Test

Schedule Your Demonstration and see how the Appsian Security Platform can be tailored to your organization’s unique objectives

Fixing PeopleSoft Workflow Email Notifications

By Chris Heller • February 7, 2009

Workflow History

When workflow was first added to PeopleSoft 5 back in 1995, the mantra was the three Rs: Rules, Roles, and Routings. I’ll bet that Rick Bergquist still has dreams where he is talking about rules, roles, and routings 🙂

Routings are the part that I wanted to highlight here. The two primary mechanisms for routings that PeopleSoft delivered as part of PeopleSoft 5 were worklists and email.

Worklists are great for people that spend a lot of time in PeopleSoft applications and have enough activity being routed to them that they actually check their worklist, but the broader audience does not typically login to PeopleSoft to check their worklist to see if there is anything waiting for them to do.

It’s sort of shame that more work didn’t happen on pushing out PeopleSoft worklist entries to whatever the end-user really use as their “stuff I need to do” list. There are some decent APIs that PeopleSoft delivers these days for accessing that data, but I’m not familiar with them being used for generically pushing PeopleSoft worklists into something like the Todo List functionality in Outlook or Lotus Notes.

In the absence of integrating their worklist entries with something else, most people ended up just using email as the primary mechanism of notifying people that they needed to do something like approve a purchase order in PeopleSoft.

Issues with Workflow Email Notifications.

There are some problems with relying on email though.

Please Do Not Reply To This Email.

Historically the emails generated by PeopleSoft came from a system account, instead of being from an actual person. So PeopleSoft customers would make sure that the emails that were sent out all had text in them telling the person “please do not respond to this email”.

Makes sense, except that the whole reason that we’re sending out emails is because of it’s universality. Getting an email that you can’t respond to is kind of like getting phone calls from the robot dialers that political campaigns use; pretty annoying.

In newer releases of PeopleSoft this is less of an issue because there are more places where application developers took advantage of the ability to generate emails themselves in PeopleCode with more control than the core workflow framework provided. In fact, the Financials/Supply Chain development group did enough of this that they wrote an entire workflow framework using PeopleCode application classes.

In PeopleTools 8.48, that code (known as Approval Workflow Engine) was moved to core PeopleTools so that all applications and customers could use them. So if you’re up on an applications release 9.0 and higher, be sure to take a look at that.

Stop Sending Me So Many Emails!

We’ve talked with a number of PeopleSoft customers over the years that have ended up turning off workflow because of user complaints regarding the sheer volume of email that they receive. In fact, we just had someone searching our blog today for how to turn off notifications in PeopleSoft HCM.

The problem is that each event that happens (purchase order is entered) and the notification is tied directly to that. Immediate notification is important in some scenarios (confirmation of a customer’s order, employee terminations, etc.), but when someone in management gets 12 expense report, 15 purchase orders, 9 regularly scheduled reports, etc. showing up in their inbox scattered during the day they sometimes get annoyed.

One way of solving this problem is to re-write your notification processes so that the event and the notification are de-coupled. When the event happens, save off the data (could be in the worklist tables or some other tables) and then have a separate process that delivers the notifications separately.

The problem with re-writing these processes is that it’s time consuming and expensive, which is why a lot of people end up just turning off the notifications altogether.

The 1990’s are calling and they want their email formats back

It’s possible to send HTML email with PeopleTools, but a lot of the delivered workflow does not take advantage of this. On top of that the lengthy hyperlinks that can be generated for navigating directly to particular place in PeopleSoft (the navigation, plus the key values for pulling up the data) are not that attractive.

Who got what and when

Generating notifications as worklist entries leaves a rich history of when the notification was created, worked on, and closed out. There are some nice delivered reports that come with PeopleTools that can show this sort of information. Take a look at the PeopleTools delivered Queries that start with WF. There are some Crystal Reports for those as well.

Tracking email notifications doesn’t happen unless it has been specifically coded into the notification process though. Lots of applications within PeopleSoft have added this functionality to key processes, but it’s very tied to specific processes. There’s no way to figure out what are all of the emails that a particular user is receiving (or see how many notifications are being generated for a particular process).

The topics discussed in this blog entry come direct from conversations that we have had with different PeopleSoft customers (especially from folks that are familiar with the email functionality in our Report Security and Distribution product; see the Report Notification section on the flash demo). Since we’ve seen continued interest in this topic, we went ahead and built something to fix it.

Announcing the Grey Sparling Email Proxy for PeopleSoft

Here is a high level overview of what the Email Proxy does:

  • It intercepts emails that PeopleSoft generates.
  • Classifies them according to your rules (who is getting it, what process is it part of, etc.)
  • Optionally rewrites the email
    • Provides nicer formatting, rewrite generated links, custom signatures, etc.
    • Combine multiple emails together (so someone that gets 20 purchase order notifications in a day can just get one summary email).

There are setup pages where you define the rules that you want for classifying the emails as well as the look and feel of the generated emails, as well as pages for being able to view the emails being generated, statistics regarding the emails, etc.

The Email Proxy server is in beta-testing now at a large PeopleSoft customer that services multi businesses with their PeopleSoft applications and should be generally available shortly.

Labels: 2009, Email, Products, Workflow

Put the Appsian Security Platform to the Test

Schedule Your Demonstration and see how the Appsian Security Platform can be tailored to your organization’s unique objectives

Taking control of your build files

By Chris Heller • January 26, 2009

Continuing on in the cool stuff we’ve been working on series, I wanted to post something about a topic that goes way, way back.

Many years ago, Dave Yoder of Rainbird asked me at a DMUG user conference about how to get variable expansion support for file name references when building a project inside Application Designer.

Without having variables that you can expand, you always have to remember to change the name of the file that will be generated each time you build records/views/indexes, etc. It’s really easy to forget and lose old copies. If you care about saving copies for yourself or for audit purposes, then it gets tiresome to always remember.

Here’s some screenshots of what we have put together to address this particular issue. The first two screenshots show the Application Designer Build Settings dialog with the build log file set to c:temp%YEAR%%MONTH%%DAY%PSBUILD_%DBNAME%.log. Here we are just changing the log file, but it works for any of the files that would get generated when doing builds in Application Designer.

The strings that are between percent signs (YEAR, MONTH, etc.) are variables that get expanded out to real values at the appropriate moment.

Here is what it looks like when you actually run the build.

As you can see, the generated log file has been created as c:temp2009126PSBUILD_PTSYS.log. Since today is January 26, 2009 and I was working in a PTSYS database, that’s exactly what we expected

There are also tokens for things like current hour, minute, second so if you like to do lots of builds in a short time frame you might want to take advantage of those as well.

In addition to things like date/time and connectivity info, there are also tokens that are supported by other Grey Sparling products.

For example, when you are using Grey Sparling Version Control for PeopleSoft you can also do things like reference which ticket number that you are currently working on. Here’s the build settings showing the log file setting as c:tempTicket-%TICKET%PSBUILD_%DBNAME%.log

After running the build (note that our version control plugin is active now; it has to be to supply the current ticket number), you’ll see that the build log file was generated as c:tempTicket-4PSBUILD_PTSYS.log. We could have included the date/time tokens as well if we had wanted to.

Now the build scripts, log files, etc. can easily be associated with the work that you are doing, and even automatically attached to the ticketing system if you want. That helps when your developers and DBAs need an audit trail of these sorts of activities. Fun to use and keeps the suits happy!

So if you run into Dave Yoder at a conference, be sure to thank him for coming up with the idea (and asking about it enough that it finally got built!)

Labels: 2009, ApplicationDesigner, Database, Products, VersionControl

Put the Appsian Security Platform to the Test

Schedule Your Demonstration and see how the Appsian Security Platform can be tailored to your organization’s unique objectives

Overlapping Text in PeopleSoft and Safari 3.x

By Chris Heller • November 14, 2008

A little while back we had a request for help from Genentech to solve an issue that was causing them fits. They have several Macs used for ESS and MSS that run Safari 3.x, the latest browser from Apple. The problem is that when Apple released Safari 3.x, they changed a tiny behavior of the DIV tag. The height attribute is now absolute instead of the minimum height. The result is that certain pages now display overlapping text.

So, the question was how to solve this problem without rewritting every page that has this issue.

The solution is extremely simple; add a style that defaults all DIV tags to set the display style to inline. In order to accomplish this on all pages, you need to add a small set of JavaScript to one of the PeopleSoft delivered scripts, for example PT_SAVEWARNINGSCRIPT. Simply open App Designer and the HTML object PT_SAVEWARNINGSCRIPT. At the head of the object add the following lines:


if ( navigator.appVersion.indexOf( "Version/3" ) > 0 &&
navigator.appVersion.indexOf( "WebKit" ) > 0 ) {
document.write('<style> div { display:inline; } </style>');
}



The code checks the version string for two things, the start of the version number (Version/3) and the browser rendering engine (WebKit). This allow us to only modify the HTML when the browser is Version 3 of the WebKit engine. That means both Safari and Google Chrome will get the extra style tag.

One caveat is that if you upgrade PeopleSoft, you will need to add this script back to the delivered HTML object.

That’s it.

Labels: DIV, Mac, PeopleSoft, Safari

Put the Appsian Security Platform to the Test

Schedule Your Demonstration and see how the Appsian Security Platform can be tailored to your organization’s unique objectives

LDAP Query Syntax Tips

By Chris Heller • September 22, 2008

I’ve had a few conversations recently about the strangeness of LDAP query syntax so I thought a post some useful information and links here. You might not have had the need to know anything about LDAP query syntax as part of working with PeopleSoft though. PeopleSoft’s delivered LDAP integration does a good job of providing some rich functionality (authenticating users, caching profiles, role memberships, etc.) without forcing you to deal with LDAP query syntax.

LDAP Queries generated by PeopleTools

For example, in the PeopleSoft Authentication Map page ( PeopleTools -> Security -> Directory -> Authentication Map ) you can select which attribute in the directory (such as sAMAccountName) should be used for looking up the user trying to log in. Under the covers, the following LDAP query string is generated (if chrisheller is trying to login):

(sAMAccountName=chrisheller)

That’s a pretty simple example though. Looking up the group membership in order to do PeopleSoft role assignment for a user shows slightly more complex LDAP queries.

  • Novell’s eDirectory wants (&(objectclass=groupOfNames)(uniquemember=chrisheller))
  • Active Directory wants (&(objectclass=group)(member=chrisheller))
  • Oracle and Netscape want (&(objectclass=groupOfUniqueNames)(uniquemember=chrisheller))

These get generated for you automatically in the delivered PeopleCode. There are some other more complicated examples, but those get the basics across.

LDAP Query Syntax

Instead of having the queries written in a form similar to how you might speak, (attribute1=value1)&(attribute2=value2), the operator (‘&’ for AND, ‘!’ for NOT, ‘|’ for OR) gets pulled to the front and the whole thing wrapped in parentheses. A good reference is Microsoft’s page on MSDN for search filter syntax, which even includes how do things like bitwise comparisons in LDAP queries. Another good article is Unlocking the LDAP Search Filter which has some good explanations to go along with the syntax.

Another good way to get familiar with some of the possibilities for LDAP queries is to look at other examples that have been posted on the internet. JiJiTechnologies has a nice list of some example LDAP search queries. For example, here is a query that returns users that do not have a manager in the directory.

(&(objectCategory=person)(objectClass=user)(!sAMAccountType=805306370)(!manager=*))

and here is a query that returns accounts that will expire in a certain amount of time (see below for more on generating datetime values for LDAP queries)

(&(objectCategory=person)(objectClass=user)(!sAMAccountType=805306370)(!accountExpires=0) (!accountExpires=9223372036854775807)(!accountExpires<=currentTime)(accountExpires<=givenTime))

What can I do with a custom LDAP query?

Well, you might want to do some custom LDAP processing yourself from PeopleCode. Maybe you want to audit the manager entry in the LDAP directory with what is stored within your PeopleSoft HCM database. You might generate LDAP queries like the following to check on a one-by-one basis

(&(sAMAccountName=chrisheller)(manager=CN=larrygrey,OU=Employees,DC=greysparling,DC=com))

(or you might dump the employee/manager attributes from the directory in bulk instead).

Maybe you want to the delivered LDAP authentication to only login users that won’t have their account expire in the next day. You could change the delivered PeopleCode in FUNCLIB_LDAP.LDAPAUTH.FieldDefault to include that check as part of the LDAP query used (note that this is a customization; there is not a place for you to add this without customizing).

As part of our Desktop Single Signon for PeopleSoft product, we also provide the ability to use attributes in an LDAP directory as part of the process of mapping a network login to a PeopleSoft account. In the LDAP configuration there are “prepend” and “append” hooks in place to be able to modify the LDAP query that our code generates.

The feature was originally added because of a PeopleSoft customer that only wanted Single Signon to apply to users that were required to login with a Smartcard. If the user’s account wasn’t setup to require a Smartcard to login, then they wanted Single Signon to not establish their PeopleSoft session, and instead leave them at the PeopleSoft login page.

The attribute in Active Directory that contains the needed information is called userAccountControl. Unfortunately, this attribute is actually a bitfield, so we have to apply the bitwise operators that I mentioned above. In the Single Signon configuration they added a prepend value of (&(userAccountControl:1.2.840.113556.1.4.803=262144) and the append value of ) (that’s a single parentheses to close off the query).

At runtime, the generated LDAP query would have been (sAMAccountName=chrisheller), but with the prepend and append values added in, the query becomes (&(userAccountControl:1.2.840.113556.1.4.803=262144)(sAMAccountName=chrisheller)).

In case you haven’t memorized the MSDN documentation link from above yet (it’ll be on the midterm), the “:1.2.840.113556.1.4.803” part is the bitwise AND operator, which we are applying to the userAccountControl attribute. The 262144 is the decimal value for the “Smart card required for login” setting (also known as ADS_UF_SMARTCARD_REQUIRED). Here is a good list of the various different bitvalues that can be in the userAccountControl field.

So now when the LDAP query runs as part of the Single Signon user mapping, if the user’s account does not mandate Smartcard login, then the LDAP query will not return a match, which means that the user will not be automatically logged in to PeopleSoft.

Converting date/time values between Active Directory and PeopleCode

I have some PeopleCode written for this, but it’s getting late so I’ll save that for another post. If you’re interested in it, leave a comment. For now, I’ll just leave it as saying that this writeup on Active Directory’s Integer8 attributes by Richard Mueller was extremely helpful in coming with it.

(update : here is a post that provides the PeopleCode for handling all of the datetime conversions between ActiveDirectory format and PeopleCode datetime variables).

Labels: 2008, LDAP, Security

Put the Appsian Security Platform to the Test

Schedule Your Demonstration and see how the Appsian Security Platform can be tailored to your organization’s unique objectives

PeopleSoft telephony two factor authentication

By Chris Heller • July 7, 2008

(update : check out demo 4 in the Flash demo for our ERP Firewall to see some additional real world examples of multi-factor authentication for PeopleSoft)

At the end of the previous blog entry on PeopleSoft telephony integration, we were able to initiate telephone calls from within PeopleCode to an end user and prompt them to enter a PIN code so that we could authenticate them. We could even see in the logs whether the user typed the correct PIN on their phone or not.

What we didn’t cover was how we can figure out in PeopleCode whether the user typed the correct PIN or not. If we can’t do that, then there’s not much point to the whole exercise, eh? 🙂

To make a long story less long, you can’t (easily) find out the answer with just PeopleCode. There are a couple of reasons for this. One was hinted at yesterday; the Asterisk Manager API call origination only allows you to get the call going. Once the call has been successfully initiated, then the call origination reports success. Even if the user does not answer the phone, the call itself was successfully originated.

If you want to find out what happened, then you have to use another part of the Asterisk Manager API, the events API. That allows you to listen to various events happening within Asterisk. So after we originate the call, there will be a series of events triggered (Dial events, Hangup events, Callerid events, etc.) that we can use.

The good news is that the Asterisk-Java library that we’re using has great support for the events API. There are Java classes for all of the different events that occur within the Asterisk server. For example, here’s someone else’s sample Java code of catching the Dial event and using that for screenpops.

In order to register which events that you are interested in though, the Asterisk-Java library require you to implement a Java interface called ManagerEventListener. Implementing interfaces is no big deal when you’re writing Java code; it’s just a list of methods that you have to provide the actual code for. However PeopleCode can’t implement Java interfaces, so we’re going to need to write some Java code ourselves.

In order to make this work, I needed to create two separate Java classes. The first one is called PSoftLoginManager. In addition to implementing the ManagerEventListener interface, I moved the PeopleCode logic for doing the call origination into this class as well.

The other class that I needed to create is called PSoftLoginEvent and it extends the delivered UserEvent class. The Authenticate command that we are using in Asterisk does not actually create any events for us to listen to. However, Asterisk supports the notion of user defined events, so we can use that. At the moment the PSoftLoginEvent includes the PeopleSoft user ID and whether the login attempt was successful or not.

The Java code wasn’t too bad. 100+ lines or so, but let’s look at how the PeopleCode looks now first. All of the variable declarations at the top stay the same, but the rest of the code is now just

Local JavaObject &loginMgr = CreateJavaObject("com.greysparling.asterisk.PSoftLoginManager", &host, &user, &pswd);
Local JavaObject &loginEvt = &loginMgr.challengeUser(&userID, &phone, &pinCode, &channel, &context, &exten);
If &loginEvt.isSuccess() Then
Warning ("Successfully validated user " | &userID);
Else
Warning ("Off with " | &userID | "'s head!");
End-If;



We create our PSoftLoginManager object with the Asterisk server information, and then call challengeUser to initiate the call and get the result back. Instead of having challengeUser return a binary result of success or not, I return the actual PSoftLoginEvent object itself which can be queried for success or failure. That keeps things easy later if we need to expose any additional data back from the Asterisk side.

On the Asterisk configuration side, we need a small change in order to trigger our login event.

[challenge-psft-user]
exten = 7189,1,Answer()
exten = 7189,2,Playback(vm-intro)
exten = 7189,3,NoOp(Authenticating user ${PSFTUSERID})
exten = 7189,4,Authenticate(${PIN},j)
exten = 7189,5,NoOp(Successful login ${PSFTUSERID})
exten = 7189,6,UserEvent(PSoftLogin|userId: ${PSFTUSERID}|result: SUCCESS)
exten = 7189,7,Hangup()
exten = 7189,105,NoOp(Unsuccessful login ${PSFTUSERID})
exten = 7189,106,UserEvent(PSoftLogin|userId: ${PSFTUSERID}|result: FAILURE)
exten = 7189,107,Hangup()



The main difference is the use of the Asterisk UserEvent command. That takes the name of our login event as it’s first parameter. The additional parameters are the ones that we have defined for our event. The Asterisk-Java library will automatically map these extra parameters that we have defined into the appropriate setter calls on the Java PSoftLoginEvent object (e.g. userId maps to setUserId() ).

Now when we run the App Engine program, here’s what the Asterisk console looks like.

    -- Executing [7189@challenge-psft-user:1] Answer("IAX2/123456789-2", "") in new stack
-- Executing [7189@challenge-psft-user:2] Playback("IAX2/123456789-2", "gs-demo-login") in new stack
-- Playing 'gs-demo-login' (language 'en')
-- Executing [7189@challenge-psft-user:3] NoOp("IAX2/123456789-2", "Authenticating user PTDMO") in new stack
-- Executing [7189@challenge-psft-user:4] Authenticate("IAX2/123456789-2", "4554|j") in new sta ck
-- Playing 'agent-pass' (language 'en')
-- Playing 'auth-thankyou' (language 'en')
-- Executing [7189@challenge-psft-user:5] NoOp("IAX2/123456789-2", "Successful login PTDMO") in new stack
-- Executing [7189@challenge-psft-user:6] UserEvent("IAX2/123456789-2", "PSoftLogin|userId: PTDMO|result: SUCCESS") in new stack
-- Executing [7189@challenge-psft-user:7] Hangup("IAX2/123456789-2", "") in new stack
== Spawn extension (challenge-psft-user, 7189, 7) exited non-zero on 'IAX2/123456789-2'
-- Hungup 'IAX2/123456789-2'



You can see the addition of the UserEvent here, plugged in with the name of our event, the PTDMO user and the result value of SUCCESS. Since this event is what our challengeUser function returns to PeopleCode, we can now properly do the two factor authentication from PeopleSoft.

Here’s the Java code for the PSoftLoginEvent class. The things that are worth noting is that it extends the org.asteriskjava.manager.event.UserEvent class, and that it has setters for the values that we want to receive. It appears as though you can only get strings from the Asterisk side, so I adopted the convention that result has to be the string SUCCESS for a successful login.

package com.greysparling.asterisk;

import org.asteriskjava.manager.event.UserEvent;

public class PSoftLoginEvent extends UserEvent {

private String userId;
private String result;

public PSoftLoginEvent(Object source) {
super(source);
}

public String toString() {
return "PSoftLogin for " + getUserId() + " (" + result + "),"
+ super.toString();
}

public boolean isSuccess() {
return "SUCCESS".equals(result);
}

public void setResult(String result) {
this.result = result;
}

public String getUserId() {
return userId;
}

public void setUserId(String userId) {
this.userId = userId;
}

private static final long serialVersionUID = 1L;

}


Here is the Java code for the PSoftLoginManager class. This is a little bit more complex, but not too bad. We implement the ManagerEventListener class so that the Asterisk-Java library knows we want to receive events. That means that we have to provide an “onManagerEvent” method.

Our implementation of onManagerEvent is pretty simplistic – we just check if the event is a PSoftLoginEvent, and whether the user ID in that event matches the one that we just sent. A more robust implementation would use some unique IDs for matching up the exact logins; not just check the user ID. We’d also want to check for other related events such as the user hanging up without even trying to enter the PIN code.

Another thing worth pointing out here is that in the Asterisk-Java library, event notifications come in on a different thread. PeopleCode only runs single threaded, but when you are calling Java from within PeopleCode, there may be multiple threads running from within the Java Virtual Machine.

In this demo implementation, we’re cheating a bit by just sleeping on the main thread while we wait for the login event to come back. It works just fine for our purposes here, but it’s definitely not production ready code. We’d probably also want to have some sort of a connection pool instead of logging in to the Asterisk server on every request.

package com.greysparling.asterisk;

import java.io.IOException;
import java.util.HashMap;

import org.asteriskjava.manager.AuthenticationFailedException;

import org.asteriskjava.manager.ManagerConnection;
import org.asteriskjava.manager.ManagerConnectionFactory;
import org.asteriskjava.manager.ManagerEventListener;
import org.asteriskjava.manager.TimeoutException;

import org.asteriskjava.manager.action.OriginateAction;
import org.asteriskjava.manager.event.ManagerEvent;
import org.asteriskjava.manager.response.ManagerResponse;

public class PSoftLoginManager implements ManagerEventListener {

private ManagerConnection connection;
private boolean keep_running = true;

private String userId;
private PSoftLoginEvent event;

static final String USERID = "PSFTUSERID";

static final String PIN = "PIN";

public PSoftLoginManager(String host, String user, String pswd) throws
AuthenticationFailedException, TimeoutException, IOException {

ManagerConnectionFactory factory =
new ManagerConnectionFactory(host, user, pswd);

connection = factory.createManagerConnection();
connection.addEventListener(this);

connection.registerUserEventClass(PSoftLoginEvent.class);
connection.login();
}

public PSoftLoginEvent challengeUser(String userId, String phone,
String pinCode, String channel, String context, String exten)

throws InterruptedException, TimeoutException, IOException {

this.userId = userId;
this.event = null;

HashMap vars = new HashMap();

vars.put(USERID, userId);
vars.put(PIN, pinCode);

OriginateAction action = new OriginateAction();
action.setChannel(channel + "/" + phone);

action.setContext(context);
action.setVariables(vars);
action.setExten(exten);

action.setPriority(new Integer(1));

ManagerResponse response = connection.sendAction(action, 30000);

System.out.println(response.getResponse());

while (keep_running)
Thread.sleep(100);

return this.event; // caller can check isSuccess()

}

public void onManagerEvent(ManagerEvent event) {
if (event instanceof PSoftLoginEvent) {

PSoftLoginEvent login_event = (PSoftLoginEvent)event;
System.out.println("Login event: " + login_event);

if (userId.equals(login_event.getUserId())) {
System.out.println("Matched user");
this.event = login_event;
this.stop();
}

else {
System.out.println("User was " + login_event.getUserId());
}
}
else {
System.out.println("Event: " + event);
}
}

public void stop() {
keep_running = false;
}

}



So there you have it. We’ve successfully made phone calls from within PeopleSoft, challenged user for a PIN code, and take action accordingly. Everything that we need for two factor authentication of PeopleSoft users, and our total cost is still under one dollar.

(updated with syntax highlighting)

Labels: , , , , ,

Put the Appsian Security Platform to the Test

Schedule Your Demonstration and see how the Appsian Security Platform can be tailored to your organization’s unique objectives

PeopleSoft IVR Integration the easy way

By Chris Heller • July 6, 2008
Yesterday’s blog post on Java 5 and PeopleTools 8.49 (and my high hopes that it would have fixed something that been annoying me) didn’t have a happy ending. PeopleTools doesn’t (yet) take advantage of the some of the Java 5 features, so we have to stick with some workarounds for the time being. PeopleTools 8.49 using Java 5 does provide me another good new thing to work on though. The open source Asterisk-Java library requires Java 5 at a minimum, but with PeopleTools 8.49, that’s OK. What the library provides is a good Java level interface into the open source Asterisk telephony platform. There’s tons of material about Asterisk available, both online and printed books, so this blog post won’t go into too much background on it. If you want to follow along though, you can’t go wrong with the different downloadable Asterisk appliances out there (PBX in a Flash, AsteriskNOW, etc.). This blog post is actually sort of a lead-in for one of the sessions that I submitted for this year via Mix was called “Telephony Integration with PeopleSoft on the cheap”. I don’t know whether that session will actually make it in for OpenWorld (there are an astounding number of sessions that have been submitted via Mix), but it’s a good topic, so I thought I’d start blogging it. For this blog post, what we want to do is be able to initiate a phone call to the end user from PeopleSoft, prompt them for a PIN code, and take action in PeopleSoft depending on whether they were successful or not. We may want to do this as part of the initial signon process for two-factor authentication of your PeopleSoft users, or we might tie this in with some business logic (e.g. be really sure who is sending off a large wire transfer). For the business logic use case, we recommend that you utilize an application firewall to simplify the configuration and maintenance of it. Our own ERP Firewall for PeopleSoft product has a demonstration on our product page of doing 2-factor authentication using Instant Messaging technology (a similar technique to that used here). For testing, I always like to whip up an App Engine test program for playing around. Let’s take a look at our first attempt at the code, then we’ll look at the Asterisk configuration.
REM Connectivity to Asterisk server. ;
REM Assumes that &user has been granted access to Asterisk Manager API;
Local string &host = "192.168.1.200";
Local string &user = "asterisk_user_id";
Local string &pswd = "asterisk_password";

REM Asterisk information for how we will be originating phone calls;
Local String &voip_provider_acct = "123456789</code><code>";
Local string &channel = "IAX2/" | </code><code>&voip_provider_acct</code><code>;
Local string &context = "challenge-psft-user";
Local string &exten = "7189";

REM The phone number that we will be calling;
REM This would normally come out of the user's profile;
Local string &phone = "15105551212";

REM The PeopleSoft userID of the person to call;
Local string &userID = "PTDMO";

REM This PIN could be autogenerated or stored in the DB;
Local string &pinCode = "4554";


REM ******** No more user variables below here *********** ;
Local string &base = "org.asteriskjava.manager.";
Local JavaObject &connectFactory = CreateJavaObject(&base | "ManagerConnectionFactory", &host, &user, &pswd);

Local JavaObject &connection = &connectFactory.createManagerConnection();
&connection.login();

Local JavaObject &originateAction = CreateJavaObject(&base | "action.OriginateAction");
Local JavaObject &vars = CreateJavaObject("java.util.HashMap");
&vars.put("PIN", &pinCode);
&vars.put("PSFTUSERID", &userID);
&originateAction.setChannel(&channel | "/" | &phone);
&originateAction.setContext(&context);
&originateAction.setVariables(&vars);
&originateAction.setExten(&exten);
&originateAction.setPriority(CreateJavaObject("java.lang.Integer", 1));

Local JavaObject &originateResponse = &connection.sendAction(&originateAction, 30000);
Warning (&originateResponse.getResponse());
After setting up a bunch of variables that we’ll need, the code begins by connecting to the Manager API of our Asterisk server. We’ll need a user/password here that has appropriate access to the Manager API; there probably won’t be any in your default install of Asterisk so you’ll need to add one. This is not an end-user account though; it’s a service account that should be treated with the appropriate security. The other configuration note here is that the Manager API lets you limit access with an IP address range for each user, so in addition to having a strong password, you should limit the user to only be able to connect from your PeopleSoft servers. After that, the code creates a call origination object. The Asterisk Manager API allows us to originate a call between a channel and an extension that is the Asterisk dialplan. A channel can be a lot of things (different Voice over IP protocols, regular phone network, etc.). In this case, I’m using a IAX2 channel that I’ve previously defined in Asterisk to use a VoIP (Voice over Internet Protocol) connection to the outside world. IAX2 is an Asterisk specific protocol similar to the more commonly known standard SIP (for example, both Oracle and BEA have SIP servers). The nice thing is that you don’t need to know too much about the channel details for experimentation purposes though. For example, for this test, I use a pay-by-the-drip VoIP provider called CallWithUs. There’s other providers out there (and we use some of those also), but CallWithUs have a nice web based provisioning system. Sign up through their webpage, send ’em some money, and you’re all set. You then supply the info that they give you to Asterisk, so when you ask Asterisk to make a call, it can send it along through CallWithUs, who then connect the call. If you’re using one of the Asterisk appliances, then you can probably get your first call happening in 30-60 minutes or so. The nice thing about doing it this way is that this can all be running on standard computer equipment. Everything that we’re doing is software based, and CallWithUs deal with the part of actually connecting to “real” phone system. As part of the channel definition for the Asterisk Manager API, we add the end-user’s phone numb er to our “dial string”, which Asterisk sends off to CallWithUs, who make the phone call to the end user. That’s one half of the call equation; my mobile phone is now ringing! Here’s what we see in the Asterisk console with the logging turned up.
  == Parsing '/etc/asterisk/manager.conf': Found
== Manager 'asterisk_user_id' logged on from 192.168.1.11
-- Call accepted by 64.85.163.184 (format ulaw)
-- Format for call is ulaw
As soon as I answered the phone, then the Asterisk console shows
      > Channel IAX2/123456789-2 was answered.
If you’ll remember our original requirements, we needed some programmatic validation of a PIN code through the phone. The cool thing about Asterisk is that there are tons of built-in options for how you handle a call coming in. Here’s a snippet from the Asterisk configuration. This defines what Asterisk calls a “context” and what to do with a call into that context for extension 7189. The name of the context and the extension don’t really matter; we just need for our PeopleCode to match up with Asterisk has.
[challenge-psft-user]
exten => 7189,1,Answer()
exten => 7189,2,Playback(gs-demo-login)
exten => 7189,3,NoOp(Authenticating user ${PSFTUSERID})
exten => 7189,4,Authenticate(${PIN},j)
exten => 7189,5,NoOp(Successful login ${PSFTUSERID})
exten => 7189,6,Hangup()
exten => 7189,105,NoOp(Unsuccessful login ${PSFTUSERID})
exten => 7189,106,Hangup()
One thing that may be a little confusing here is that we’re using Asterisk from two sides. One is our code that is calling the Asterisk Manager API that is initiating the call between my mobile phone and this context/extension definition within Asterisk. However, the Manager API is just initiating the call and then it’s done. The context/extension definition within Asterisk then says what to do with the call to this context/extension. Line 1 of the context/extension definition says to Answer the call. Line 2 plays a message that explains what is happening. On my mobile phone, I hear “This is the Grey Sparling demo login. “. Line 3 just logs what is happening on the Asterisk console. We use one of the variables that was set in the PeopleCode side so that we can match up calls with the PeopleSoft user accounts. Line 4 is a builtin Asterisk command to challenge the user to type in a PIN code. Here we’re using the PIN code that was set from the PeopleCode side. There are a series of voice prompts already delivered in Asterisk that get played as part of this as well as Asterisk “listening” for the DTMF tones from the buttons on the phone being pushed. You can roll your own handling of this within Asterisk (speech recognition anyone?), but the Authenticate command has a lot of built-in functionality for free so we make use of that. One strange thing worth mentioning here is the “j” parameter after the PIN code. That tells Asterisk to jump “+101” if the command fails (it continues on the next line if successful). It’s a bizarre form of GOTO (note that there are other ways of adding logic to Asterisk though). Then we log what happened on the console (depending on whether we get the right PIN code or not) and then hangup the phone. Here’s what the Asterisk console looks like with an invalid login.
    -- Executing [7189@challenge-psft-user:1] Answer("IAX2/123456789-2", "") in new stack
 -- Executing [7189@challenge-psft-user:2] Playback("IAX2/123456789-2", "gs-demo-login") in new stack
 --  Playing 'gs-demo-login' (language 'en')
== Manager 'asterisk_user_id' logged off from 192.168.1.11
 -- Executing [7189@challenge-psft-user:3] NoOp("IAX2/123456789-2", "Authenticating user PTDMO") in new stack
 -- Executing [7189@challenge-psft-user:4] Authenticate("IAX2/123456789-2", "4554|j") in new stack
 --  Playing 'agent-pass' (language 'en')
 --  Playing 'auth-incorrect' (language 'en')
 --  Playing 'auth-incorrect' (language 'en')
 -- Executing [7189@challenge-psft-user:105] NoOp("IAX2/123456789-2", "Unsuccessful login PTDMO") in new stack
 -- Executing [7189@challenge-psft-user:106] Hangup("IAX2/123456789-2", "") in new stack
== Spawn extension (challenge-psft-user, 7189, 106) exited non-zero on 'IAX2/123456789-2'
 -- Hungup 'IAX2/123456789-2'
We can see that in this instance I didn’t type in the PIN code correctly, so I wouldn’t have been granted access. Here’s the relevant bits from the Asterisk console of a successful login.
    --  Playing 'agent-pass' (language 'en')
  --  Playing 'auth-thankyou' (language 'en')
  -- Executing [7189@challenge-psft-user:5] NoOp("IAX2/123456789-3", "Successful login PTDMO") in new stack
  -- Executing [7189@challenge-psft-user:6] Hangup("IAX2/123456789-3", "") in new stack
But how do we find that out within the PeopleCode side so that we can actually take action? That will have to wait until part 2 One final note here. I mentioned that CallWithUs is pay by the drip. One reason that is important is because the pay by the drip VoIP providers are typically more open to initiating multiple calls at once (since you’re not paying a flat fee), which is something that you’d need for doing this for authenticating users. Once you’re comfortable with doing this sort of thing, then you might want to get your own internal phone folks involved, but since this sort of thing is fairly uncommon at this point, you’ll probably be on your own for your initial experiments in this. The nice thing is that it’s fairly cheap though. For each call to my mobile phone that was initiated while testing this I paid US$0.0125. So you get 80 login attempts for a buck 🙂

Put the Appsian Security Platform to the Test

Schedule Your Demonstration and see how the Appsian Security Platform can be tailored to your organization’s unique objectives

Request a Demo

Start your free demo

"Learn how you can reduce risk with rapid threat protection, audit response and access control. All from a single, comprehensive platform"

Trusted by hundreds of leading brands