Dynamic PeopleSoft Security Based on Login

By Chris Heller • January 19, 2006

(update : see ERP Firewall for PeopleSoft)

A few years back I had the opportunity to help out with an interesting customer requirement for dynamic security based on where the user is logging in from. Kirk Chan (another ex-PSFT person) and I got to spend quite a bit of time working with the customer on this. In the end, it was quite successful. In fact, they even presented on this at one of the PeopleSoft Connect user conferences.

The customer was rolling out PeopleSoft eBenefits to tens of thousands employees, a large number of whom didn’t have access to the corporate network except over the public internet. The challenge was that they didn’t want to take any chance that, for example, the VP of HR logs in from a kiosk machine somewhere to do his or her benefits, gets their password swiped, and then someone has access to all of the HR system. So anyone logging in over the internet was to only get the needed privileges for accessing the eBenefits pages, and nothing else. If they logged in from the internal network, then they would receive their usual access level.

Making matters more complicated was that they were about 30 days from their code freeze cut-off date for what would be rolled out. The benefits open enrollment period wasn’t something that can be changed just for dealing with code changes. If this couldn’t be implemented, then they would have to go back to doing things the old way (where most employees would fill in their info on paper). That would be pretty expensive.

Another complication was that their IT group was definitely in the “show me” mood. Later on, we were able to speculate why they didn’t have much confidence in their software vendors at that moment 🙂

So, how’d it work?

The key to this was some custom signon PeopleCode, a couple of extra tables for storing some additional data and a couple of modifications to the one of the delivered security maintenance pages. We got lucky in that they had an ex-PSFT person onsite doing some consulting who helped with the actual implementation of the code for them (Hi Maverick!). What I’m about to describe is actually simpler than what they did because of some additional requirements of theirs (users being able to opt out completely from their account being exposed over the Internet) that I won’t go into in any detail here.

(update: see this blog entry for more things to consider in looking at this customization)

What the signon PeopleCode did was to check which servers they were coming through (this is accessible in the %Request object) and then populate the PSROLEUSER table for them based on that.

The PSROLEUSER table is the table that PeopleTools uses to know what roles a user has. All of the delivered dynamic role stuff (sourcing roles via Query, or LDAP or a custom PeopleCode program) all populate this table.

This is important to understand – if there isn’t an entry in this table for a given user/role combination, then the user does NOT have that role. At runtime this is the only place that is checked for roles. The Internet Architecture does not run any queries or access LDAP servers to determine the roles, they always come from the PSROLEUSER table. You can test this out by deleting rows from this table in a demo system while you are logged in. You will lose the role(s) immediately. Unfortunately the internal PeopleTools code for handling roles that change in mid-session is really bad from a usability perspective – it’s not graceful at all).

Once we know which server the user is coming through, the signon PeopleCode would flush the existing list of roles for that user, and then re-populate it from a shadow table that was created. The shadow table was essentially a clone of PSROLEUSER, but it served to act as the “master” list of the overall set of roles that a user had. The signon PeopleCode would filter this list based on what roles were deemed appropriate for the server that the user was logging in through.

In order to keep this shadow table up to date, the delivered page for maintaining user/role combinations had to be updated to store it’s changes into the shadow table instead of PSROLEUSER. The delivered programs that source role info from Query and/or LDAP also needed small changes to write into the shadow table and not PSROLEUSER.

In a nutshell this work splits out the notion of overall roles and current roles. With the delivered PeopleSoft configuration, these two are tightly linked together. Fixing this was one of the things that was likely for PeopleTools 9.

(note: there are some other ways to do this without changing the delivered objects, but they get a little tricky and the customer didn’t care about the slight bit of extra maintenance in exchange for this functionality).

This particular problem was very focused on the notion of dynamic security based upon whether someone was logging in from inside the firewall or not, but it would be easy to extend it to other scenarios, such as the time someone was logging in. An example might be a student intern in the HR department only gets HR system access during their assigned intern hours, but they’re given access to the Student Admin pages 24/7.

Another scenario would be how the user was authenticated. If someone logs in using a SecurID token, you might grant them a higher level of access than if they only used a username and password.

There’s another scenario where this technique could be applied, but it’s probably worth it’s own blog post because there’s a couple of different ways of solving it.

Labels: PeopleCode, 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

Why You Should Avoid PeopleCode For Row Level Security

By Chris Heller • October 16, 2005

In the previous post about row level security, I mentioned that the two PeopleCode events SearchInit and SearchSave were not intended for providing row level security.

There’s a few different reasons. One key reason is that, by design, online security that is implemented via SQL is security that can be re-used for reporting. Query, Crystal, and nVision will all use the same search record/view when it is attached to tables being reported on. Crystal and nVision do this because they use Query as a data source (note that nVision is not limited to just Query as a data source though).

All you need to do is open the record properties in Application Designer. On the Use tab, you’ll see a prompt for Query Security field. Unfortunately, this prompt is not smart enough to limit your choices only to records that will make sense as security records (same keys, plus OPRID or OPRCLASS), but that won’t stop you from using the same search record/view that you used for the online component.

The next time that you run a Query, Crystal or nVision report that uses that data table, you’ll see that the data is limited appropriately. Even with SQR, where this doesn’t happen automatically, you can perform the join manually to implement this security.

If the data level security is written in PeopleCode, then you’ll have to do extra work for reporting security.

An even more important reason to avoid using SearchInit and SearchSave is to avoid potential security breaches.

Historically the behaviour of the component processor had been that if all of the key values for the search record were provided and the search record/view allowed access, then the SearchInit and SearchSave events did not fire. And why would they, given that there is no need to display a dialog to help someone browse for data that they have already supplied?

Of course, there were a number of people that did make this assumption, so the default behaviour of the component processor was changed awhile back to always force SearchInit and SearchSave to fire.

One consequence of this change in behaviour was that sending someone a URL directly into a page with the data loaded stopped working. Instead the person would see the search dialog with the key values loaded, and they would need to press the “Search” button. Since all of the keys needed to load the page were already present, the user wouldn’t need to select from multiple rows, but it was still a pretty jarring experience for the user.

So, another change was added. This time a new PeopleCode function called SetSearchDialogBehaviour() was added. The function could only be used in the SearchInit event and would allow the application developer control over whether the component processor used the historic behaviour and go straight into the page when all key values were supplied, or to keep the new default behaviour.

In case you’re wondering, there wasn’t an easy way to make the events fire, but still let the page load if all key values were provided (long explanation, but it was considered the most desirable outcome – just couldn’t happen in the releases that needed to be changed).

The problem comes because the reason for this behaviour is still not widely known in the Application Developer community. So you’ll see questions like this along with answers like this. Right answer, but not getting the overall story.

I once had to fly 3000 miles for a meeting with a large PeopleSoft customer that made this mistake in some custom development that they had a consulting company do for them. Only they didn’t figure this out themselves, a major newspaper wrote an article about the holes in the system that allowed anyone to look at anyone else’s data. Not good.

That’s not to say that it’s impossible to do row level security in PeopleCode, but in general you’re better off using the mechanisms that were intended for security.

Labels: PeopleCode, 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