Autologin for demonstration applications

Von Tobias Arnhold 1.10.2016
Why would you need an "auto login"? Can't it be configured in APEX?
In APEX you have a setting to configure the maximum session length. But this setting only lasts a certain time (12 hours as most).

The setting can be found under Supporting Objects > Security Attributes > Session Management:



But in some use cases you don't want the application to log out and to manually re-login again.

An "auto login" can come in handy for the following application examples:
 - "A one page read only application", on a big TV screen
 - "A demonstration application", for conferences

Example how it may work!
What you would need is to re-login before the session length is up and your session is kicked.

I needed some time to figure out the way how to do it. But the solution, for the examples I described above, is secure enough.

The magic trick is to send certain information to the login screen before the session length is up. To do this you will need a cookie.

So what you need is some PL/SQL code on page 101, 2 Application Processes and 2 Application Items.
-- Application Items:
-- AI_START_TIME
-- AI_RELOGIN_IN_MINUTES

-------------------------------------------------------------------------
-------------------------------------------------------------------------

-- Application Process 1: AP_INIT
-- Process Point: After Authentication
-- Type: PL/SQL Anonymous Block

:AI_START_TIME := to_char(sysdate,'dd.mm.yyyy hh24:mi:ss');

:AI_RELOGIN_IN_MINUTES := 1; -- Minutes after the relogin should start

-------------------------------------------------------------------------
-------------------------------------------------------------------------

-- Application Process 1: AP_RELOGIN
-- Process Point: On Load: Before Header
-- Type: PL/SQL Anonymous Block

declare
  v_relogin_hash varchar2(100);
  v_url          varchar2(200);
  
  v_relogin_time       date;
  v_cookie_expire_time date;
begin

-- Set date variables
v_relogin_time := sysdate-(to_number(:AI_RELOGIN_IN_MINUTES)/ 24/ 60);
v_cookie_expire_time := sysdate + (case when to_number(:AI_RELOGIN_IN_MINUTES)-1 = 0 then 1 else to_number(:AI_RELOGIN_IN_MINUTES)-1 end / 24/ 60);

-- Check if a re-login is necessary because the time run out
if :AI_START_TIME is not null and v_relogin_time > to_date(:AI_START_TIME,'dd.mm.yyyy hh24:mi:ss') then 
  -- Create hash value
  -- Including: Username, Some kind of Hash-Password, and the SYSDATE with minutes so that the HASH will only be valid for one minute.
  -- Description about Hashvalues: http://stackoverflow.com/questions/22533037/how-to-call-oracle-md5-hash-function
  select  
    rawtohex(
    DBMS_CRYPTO.Hash (
        UTL_I18N.STRING_TO_RAW (lower(:APP_USER)||'ReloginPWforHashGeneration'||to_char(sysdate-5, 'dd.mm.yyyy hh24:mi') , 'AL32UTF8'),
        2)
    ) 
  into v_relogin_hash
  from dual;             
 
  -- Create cookie
  -- Example/Description: https://apex.oracle.com/pls/apex/f?p=155555:1
  owa_util.mime_header('text/html', FALSE);  
  
  owa_cookie.send(
    name => 'C_LOGIN_USER',  
    value => lower(:APP_USER),  
    expires => v_cookie_expire_time
  );
  
  owa_cookie.send(
    name => 'C_LOGIN_HASH',  
    value => v_relogin_hash,  
    expires => v_cookie_expire_time
  );
  
  -- Logout procedure
  apex_authentication.logout(:SESSION, :APP_ID);
  
  -- Stop further execution of code
  apex_application.stop_apex_engine;

end if;

end;

-------------------------------------------------------------------------
-------------------------------------------------------------------------

-- Page 101: Autologin
-- Process Point: On Load: Before Header
-- Type: PL/SQL Code

declare
  v_app_user varchar2(100);
  v_password varchar2(100);
  v_relogin_hash varchar2(100);

  v_cookie_hash owa_cookie.cookie;
  v_cookie_user owa_cookie.cookie;
begin 
  -- read cookie
  v_cookie_hash  := owa_cookie.get('C_LOGIN_HASH');
  v_cookie_user  := owa_cookie.get('C_LOGIN_USER');
  
  -- check if an cookie exist
  if v_cookie_user.num_vals != 0 then
      -- Create Hash value
      select 
        rawtohex(
        DBMS_CRYPTO.Hash (
            UTL_I18N.STRING_TO_RAW (lower(v_cookie_user.vals (1))||'ReloginPWforHashGeneration'||to_char(sysdate-5, 'dd.mm.yyyy hh24:mi'), 'AL32UTF8'),
            2)
        ) 
      into v_relogin_hash
      from dual;
      
-     -- Debug in a text area on page 101
      -- :P101_COMPARE_HASH := 'New_'||v_relogin_hash||' Old_'||v_cookie_hash.vals (1);

      -- Compare Hash values
      if v_cookie_hash.vals (1) = v_relogin_hash and v_cookie_hash.num_vals != 0  then
        -- Auto-Login
        v_app_user := v_cookie_user.vals (1);
        v_password := 'autologin'; -- Password must be saved in plaintext to be able to login 

        wwv_flow_custom_auth_std.login(
            P_UNAME       => v_app_user,
            P_PASSWORD    => v_password,
            P_SESSION_ID  => APEX_CUSTOM_AUTH.GET_NEXT_SESSION_ID,
            P_FLOW_PAGE   => :APP_ID||':1',
            P_PRESERVE_CASE => TRUE
        );

      end if;
  end if;
end;
That is all you need.

All code is written with PL/SQL.
The cookie creates a hash value including the user name, an own password and a timestamp which makes the hash value valid for one minute

Conclusion:
There are use cases as described above where it makes sense to use this solution but when you are working with normal application you shouldn't use "auto log in's" at all.

If you need an example application just write me an email.

PS:
If you search for some kind of "remember me" functionality then look at the example from Christian Rokitta: Remember Me - APEX Autologin

-------------------------------
Update - 11.01.2016:
Matt came up with another inspiring idea: