Tuesday, October 19, 2010

Custom Authentication Scheme for Oracle Application Express and Oracle Access Manager

Our customers frequently ask about how to integrate Oracle Access Manager authentication with Oracle Application Express. There is currently a thread on the Oracle Technology Network discussion forum, asking for this type of solution. It has always been my intention to present this as an official whitepaper and recommended solution from Oracle. However, I have been struggling with some Oracle Access Manager configuration issues and I simply did not want to delay any further. The "official" whitepaper and detailed instructions will have to come later.

Back in March, 2010, I took careful note of a message that Scott Spadafore on our team had sent to someone in Oracle Support. It was a generic solution for authentication via an HTTP header variable. A couple months ago, this question came up again and Tyler Muth provided me a slightly modified version of what Scott had originally authored. With some more minor modifications on my part, I can share this custom authentication scheme, which can be used with Oracle Access Manager and really any environment which will securely set a header variable to an authenticated username.

The page sentry function is:


create or replace function header_variable_page_sentry ( p_apex_user in varchar2 default 'APEX_PUBLIC_USER' )
return boolean
as
l_cgi_var_name varchar2(100) := 'REMOTE_USER';
l_authenticated_username varchar2(256) := upper(owa_util.get_cgi_env(l_cgi_var_name));
--
l_current_sid number;
begin
-- check to ensure that we are running as the correct database user
if user != upper(p_apex_user) then
return false;
end if;

if l_authenticated_username is null then
return false;
end if;


l_current_sid := apex_custom_auth.get_session_id_from_cookie;
if apex_custom_auth.is_session_valid then
apex_application.g_instance := l_current_sid;
if l_authenticated_username = apex_custom_auth.get_username then
apex_custom_auth.define_user_session(
p_user=>l_authenticated_username,
p_session_id=>l_current_sid);
return true;
else -- username mismatch. unset the session cookie and redirect back here to take other branch
apex_custom_auth.logout(
p_this_app=>v('APP_ID'),
p_next_app_page_sess=>v('APP_ID')||':'||nvl(v('APP_PAGE_ID'),0)||':'||l_current_sid);
apex_application.g_unrecoverable_error := true; -- tell apex engine to quit
return false;
end if;

else -- application session cookie not valid; we need a new apex session
apex_custom_auth.define_user_session(
p_user=>l_authenticated_username,
p_session_id=>apex_custom_auth.get_next_session_id);
apex_application.g_unrecoverable_error := true; -- tell apex engine to quit
--
if owa_util.get_cgi_env('REQUEST_METHOD') = 'GET' then
wwv_flow_custom_auth.remember_deep_link(p_url => 'f?'|| wwv_flow_utilities.url_decode2(owa_util.get_cgi_env('QUERY_STRING')));
else
wwv_flow_custom_auth.remember_deep_link(p_url=>'f?p='||
to_char(apex_application.g_flow_id)||':'||
to_char(nvl(apex_application.g_flow_step_id,0))||':'||
to_char(apex_application.g_instance));
end if;
-- -- register session in APEX sessions table,set cookie,redirect back
apex_custom_auth.post_login(
p_uname => l_authenticated_username,
p_session_id => nv('APP_SESSION'),
p_app_page => apex_application.g_flow_id||':'||nvl(apex_application.g_flow_step_id,0));
return false;
end if;
end header_variable_page_sentry;

The high-level steps to be performed are:
  1. Compile this function header_variable_page_sentry in the parsing schema of your application
  2. Create a new custom authentication scheme. In the Page Sentry Function attribute of the custom authentication scheme, enter: return header_variable_page_sentry;
  3. Add directive PlsqlCGIEnvironmentList inside the corresponding APEX Database Access Descriptor. By default, OAM Webgate uses the header variable REMOTE_USER.
  4. Secure the APEX application in Oracle Access Policy Manager by defining its corresponding Policy Domain.
  5. Back in your APEX application, make this new authentication scheme "current" for your application.

The custom authentication scheme should work in any version of Application Express. A gentleman from Oracle Consulting got this to work at a customer site using APEX 3.2 and OAM 10g. He very graciously put together a document detailing all of the steps he performed in Application Express and Oracle Access Manager to get this to work, which is invaluable to someone like me who is essentially OAM-ignorant. I've asked for his permission to share this document, and when/if I get his okay, I'll make it available from this blog.

20 comments:

Unknown said...

Hello Joel,
Thank you for your custom authentication scheme for integration OAM with APEX for SSO.

We have 2 application servers configured for one instance of APEX: WebLogic with listener and Oracle Application Server.
Could you tell me is there any way to use OAM custom scheme (Weblogic) and scheme for Application Server for SSO simultaneously?

Joel R. Kallman said...

Hi Ирина,

Are you saying that you wish to use the "old" SSO SDK with Application Server? I know that internally at Oracle they setup OAM to work with old SSO SDK applications - how they did this, though, I don't know.

Joel

runcsmeduncs said...

Joel

Thanks for posting this. We are in the process of proving our new tech stack using OAM, Webgate, APEX and native authentication using domain credentials.

Moving our current APEX Authentication scheme from Oracle SSO to OAM (via native authentication) is the last link in the chain. I will give this a go when I am back in the office on Monday.

Any update of the official white paper yet?

Duncs

Joel R. Kallman said...

Duncs,

I'll be honest with you - there has been no movement on any "official" white paper. But I can tell you that in Application Express 4.1, we will natively support header variable authentication - so this custom code in a custom authentication scheme in APEX goes away. And all that remains is configuration via Oracle Access Manager, which is really outside of our domain of expertise.

However - you're not alone in your requirement. Oracle Support is getting more and more requests for configuration with OAM 11g (and not OAM 10g, as is in this Word document). If a configuration document is produced there (and it may be), I will certainly publicize it.

Joel

Joel R. Kallman said...

Just wanted to let you know that this "official" whitepaper is now available on OTN at http://www.oracle.com/technetwork/developer-tools/apex/learnmore/index.html, in the "Technical Information and White Papers" section at the bottom.

Joel

Gayle R said...

We are trying to use HTTP header variables to authenticate an APEX user. Can anyone supply a link to some examples of how you would set this up? What types of functions must you create?

Thanks.

Joel R. Kallman said...

Gayle R,

I'm not sure what type of setup you're looking for. To be able to exploit this in APEX, it's as simple as choosing the authentication scheme of HTTP Header Variable and specifying the name of the header variable.

Many identity management solutions, like Oracle's Access Manager or even SiteMinder all will protect a set of URLs and then transmit the authenticated username in an HTTP header variable.

Joel

King Oualid said...



I am setting up an authentification scheme, type HTTP Header Variable


The informations sent by the HTTP query are: ID_USER, LAST_NAME, FIRST_NAME, EMAIL and PROFIL

Actually I get the ID_USER in APEX using the bind variable APP_USER or using the V function V('APP_USER')

My question is how to get the other informations like LAST and FIRST NAME ?

I am on APEX 4.2

Thanks in advance.

Joel R. Kallman said...

Hi King Oualid,

Assuming those values are passed via header variables, you could use owa_util.get_cgi_env to get the respective values of them (and assign them to application items, if you wish).

Joel

Anonymous said...

Hi,

We have been trying to use SAML authentication in our existing APEX application where authentication scheme type is 'HTTP Header Variable'.

One of the requirement was to validate the username(i.e email id) sent from the HTTP Header variable, and if it exists more than 20 characters use the first 20 characters before the domain name as the username.

So basically my :APP_USER should be cropped to 20 characters from the username variable. Not sure where exactly i can handle this.

Is it possible to handle it in the authentication scheme or should it be handled while passing to the HTTP Header variable itself.

Any inputs would be really helpful.

Thanks
Rebecca

Joel R. Kallman said...

Hi Rebecca,

You should be able to accomplish this with the "Post-Authentication Procedure Name" attribute of the authentication scheme. If you look at the field-level help, it includes a good example of modifying the username during Login Processing.

I hope this helps!

Joel

HIMANSHU said...
This comment has been removed by the author.
Chintan Gandhi said...

Hi Joel,

I have implemented Shibboleth authentication using above code. Login works fine.
On log out, I take user to my SSO logout page, which works fine too. This I have achieved by calling a procedure in the custom authentication's 'Post Logout Procedure Name'. Code in this procedure is as below:

procedure post_logout
is
begin
owa_util.redirect_url('https://fast.mycompany.com/ext/mylogout');
APEX_CUSTOM_AUTH.LOGOUT (
p_this_app => v('APP_ID'));
end;

After this, on accessing my application URL, I expected it to ask me to log in again on my SSO portal, but it doesn't and it takes me directly inside application (with a new session id and the same old user name).
Is my expectation incorrect in expecting it to take me to SSO login screen? If not, how can I make it to take me to SSO login screen before taking me inside application?

Please note that if I close my browser completely and re-open it and then access my application URL then it prompts me to login on my SSO portal, as expected.

Thanks,
Chintan

Joel R. Kallman said...

Hi Chintan,

What does your page sentry or custom authentication scheme look like? It sounds like you aren't extinguishing whatever determines that someone is authenticated.

Joel

Unknown said...

Hi Joel,

I am setting up an authentication scheme type HTTP Header variable in APEX application (very similar to King Oualid's post on this thread).

I need to accept two header variables (not REMOTE_USER). Let's say HEADER_VAR1 and HEADER_VAR2.

I have tried to get them using owa_util.get_cgi_env but somehow it's not fetching these two header variables.
Is there something I am missing here? does it need any extra settings? how can I get HEADER_VAR1 and HEADER_VAR2?

I will highly appreciate any of your input.

Thanks
Jignesh

Joel R. Kallman said...

Hi Jignesh,

Are your HTTP headers containing the values being passed? Can you monitor the Web traffic and see the actual requests?

Joel

Unknown said...

Hi Joel,

I am using apex 5 .I created http header variabel authentication scheme and access sso id as owa_util.get_cgi_env('OAM_REMOTE_USER').I am bale to access sso id.Can u pls guide me on how to implement sso log out.

Regards.

Keerthi.

Joel R. Kallman said...

Hi Keerthi,

Are you using this with Oracle Access Manager? If so, they have instructions how to configure centralized logout: https://docs.oracle.com/cd/E40329_01/admin.1112/e27239/logout.htm#AIAAG2191. You would just need to specify the logout URL in your APEX application.

Joel

Unknown said...

Hi Joel,

I am setting up an authentication scheme type HTTP Header variable in APEX application.

I need to accept two header variables (not REMOTE_USER). Let's say HEADER_VAR1 and HEADER_VAR2.

I have tried to get them using owa_util.get_cgi_env but somehow it's not fetching these two header variables.
Is there something I am missing here? does it need any extra settings? how can I get HEADER_VAR1 and HEADER_VAR2?

I will highly appreciate any of your input.

Thanks
marwen.

Joel R. Kallman said...

Hi Marwen,

What is your "upstream" authentication agent?

Joel