Programs running on IBM i routinely need to retrieve the specific user ID associated with the person executing the code. In traditional interactive 5250 programs, the user ID is often accessed in RPG through the program status data structure, or by making a call to a CL program that uses the RTVJOBA command. These "old school" green screen approaches for obtaining the user ID may need to be tweaked a bit when running within a web environment.
In Valence, the CGI jobs servicing the browser are initiated under a special IBM i user ID, with the current user typically overridden to the IBM i user making calls through the Portal. Thus you have at least two user concepts at play for any given CGI job at a given point in time -- the "job user" and the "current user". And for scenarios where non-IBM i users are permitted to log into the Valence Portal, you may also have a third user concept: the unique Valence login ID.
This post explains how the user override process works and how best to obtain the user ID your application needs, whether it be an RPG/CL program or an SQL-based data source.
Understanding the Different User IDs
When you initiate an interactive terminal session and log in as, say, JOHN, then your IBM i job user and your current user are both set to JOHN. You could conceivably call a program that subsequently overrides your current user to another ID, but that's not very common in the green screen world. In most cases, your job user and your current user will remain JOHN for the duration of the interactive session. Hence, accessing the job user would typically work just fine for your programs, even if you're really intending to retrieve the current user.
In the CGI world of Valence things work a bit differently when it comes to user IDs. CGI jobs are by default initiated by user QTMHHTTP, which serves as the job user for the duration of the job. Apache will then set the current user of the job to QTMHHTP1 in order to make calls to programs. In most configurations, Valence will subsequently override QTMHHTP1 to the IBM i user ID associated with the Valence login for the session. This override is handled through a "traffic cop" program called VVCALL using the vvUtility_ovrUsr procedure. The current user is then typically reset back to its original value of QTMHHTTP1 after the called program(s) have completed. These override and reset behaviors in Valence are controlled through the Portal Admin Settings of "Override job user" and "Reset job user" respectively.
Since the job user and current user are not the same in a CGI environment, your RPG and CL programs cannot assume accessing the job user would suffice for getting at the desired user ID. Some simple adjustments are necessary, which are described below.
Getting the Current IBM i User in an RPG program
A common problem we see happen when customers start calling older RPG programs from Valence is they find their programs are writing data to files with QTMHHTTP as the user ID. Most often this is because the program is accessing the job user in the program status data structure (PSDS), rather than the current user. Here are the fixed format and free form data structure definitions:
d* fixed format PSDS... d sds d jobUser 254 263 d curUser 358 367 // free form PSDS... dcl-ds pgm_stat psds; jobUser char(10) pos(254); curUser char(10) pos(358); end-ds;
Though you can clearly get to the current user as well as the job user through the PSDS, we don't typically recommend using this approach. The reason is that when a program is running in a particular activation group, the SDS is initialized the first time it's called and stays that way until the activation group is reclaimed. So when program X is called for the first time in a CGI job by user JOHN, the SDS field for the current user (Cur_User in this case) is set to JOHN and that value "sticks" for subsequent calls, even if the program is later called by user JANE.
There are two approaches to getting the current user ID that are more reliable:
(1) Use inz(*user) in a procedure...
text='Current User is '+getCurrentUser(); ... // fixed format procedure... p getCurrentUser b d pi 10a d curUser s 10a inz(*user) return curUser; p e // free form procedure... dcl-proc getCurrentUser; dcl-pi *n char(10); end-pi; dcl-s curUser char(10) inz(*user); return curUser; end-proc;
Note that you should only use inz(*user) in a procedure, not in the mainline section, as it too will only be initialized on the initial call to the program/activation group.
(2) Use SQL...
If you're working with an SQLRPGLE program, you can use a simple SQL statement to get the current user:
exec sql set :curUser = session_user;
Note that you could also use "user" instead of "session_user" in the SQL statement, as they both essentially reference the same thing, but you generally would not want to use "current_user" (see explanation below).
Getting the Current IBM i User in a CL Program
If your programs are calling an external CL program using RTVJOBA to get the user, be sure they're not using this approach:
Instead they should be using this:
Getting the Current IBM i User in an SQL Statement
When you're using SQL, i.e. as a data source in a Nitro App Builder app, there are actually four reserved words for getting at various user IDs, depending on what you're looking for:
- SESSION_USER (VarChar(128)) - returns the current user for the job.
- USER (VarChar(18)) - also returns the current user for the job.
- SYSTEM_USER (VarChar(128)) - returns the job user.
- CURRENT_USER (VarChar(128)) - returns the adopted user authorization, which may not be the "current user" as you'd expect. For example, if accessed inside a program/stored procedure that was compiled with USER=*OWNER option, it would return the owner associated with the program.
So if you were populating a form widget and wanted to include the current user in the response, your SQL statement could look something like this:
select CNAME, CSTATE, CCOUNTRY, SESSION_USER from DEMOCMAST where CUSNO=xxxxx
Getting the Valence login ID
Finally, in Valence instances that include non IBM i users logging into the Portal, your programs or apps may want to access the unique Valence login ID instead of a generic IBM i user ID. The RPG Toolkit procedure vvUtility_getCurrentUser will return the Valence login ID associated with the current session. In an RPG program, the call is fairly simple:
currentUser = vvUtility_getCurrentUser();
Note that you can pull in other elements associated with the Valence user (name, email address, etc) by passing parameters, as described in the documentation.
If you need to get at the current session's Valence login ID in an SQL-based data source, one elegant way is to create an SQL function that serves as a wrapper for this procedure. For example:
CREATE OR REPLACE FUNCTION VALENCE6.VVUTILITY_GETCURRENTUSER() RETURNS VARGRAPHIC(64) CCSID 1200 LANGUAGE RPGLE DETERMINISTIC READS SQL DATA EXTERNAL NAME 'VALENCE6/VVSRVPGM(VVUTILITY_GETCURRENTUSER)' PARAMETER STYLE GENERAL
With this function created, you can then call it in your SQL select statements. In most cases you'll want to wrap it in char() since the Valence login ID is returned as a graphic...
select CNAME, CSTATE, CCOUNTRY, char(VVUTILITY_GETCURRENTUSER()) as CURUSER from DEMOCMAST where CUSNO=xxxxx