Skip to Main Content
  • Questions
  • DBAccount Authentification via PLSQL API

Breadcrumb

Question and Answer

Chris Saxon

Thanks for the question, Carlos.

Asked: December 02, 2021 - 7:57 am UTC

Last updated: December 09, 2021 - 6:26 pm UTC

Version: 21.2

Viewed 1000+ times

You Asked

Hey,
I need a possibility to validate the user credentials from APEX Login with the database accounts. Something similar to APEX_LDAP.AUTHENTICATE. I can't use the Database Accounts built-in authentication scheme, because I use a custom authentication scheme. The reason for the custom scheme is among other things that I'd like to offer a fallback authentication for my primary LDAP authentication. If that failed, I'd like to check the credentials against the database (so the user has two possibilities to authenticate and both will work).

Here is a code snippet from my custom user_auth function:
function user_auth(
      p_username in varchar2,
      p_password in varchar2)
    return boolean
  is
    c_username dbms_id_128 not null:=p_username;
    c_password dbms_id_128 not null:=p_password;
    lv_is_authenticated boolean:=false;
  begin
    -- 1) try ldap
    lv_is_authenticated:=apex_ldap.authenticate(p_username => c_username, 
                                                p_password => c_password,
                                                p_search_base => '...',
                                                p_host  => '...');
    -- 2) if failed try dbaccounts
    if not lv_is_authenticated then 
      lv_is_authenticated:=NEED_HELP_FROM_ASK_TOM.DB_AUTHENTICATE(...);
    end if;
    
    return lv_is_authenticated;
  end user_auth;


Thanks for your help...

and Chris said...

I strongly urge you to abandon this idea.

Doubling up on authentication methods brings all sorts of problems & risks, such as:

- You're storing the password in two places; this increases the attack surface and chance of a leak
- Password synchronization - how do you ensure password changes apply to both places at the same time?
- Any custom authentication scheme is highly likely to be less secure than LDAP

If LDAP is down, that sounds like a priority zero, drop everything to get it working again type of situation to me. Building a "just in case" fallback doesn't seem worth it to me.

If you absolutely must go ahead with this (again - please don't!) then the basic process is:

- Create a users table to store the HASH of the password + username + salt
- To authenticate users, repeat the hashing process used above on the supplied credentials
- Query the users table for this account and check if the hashes match
- If they do => success, if they don't => failure

Here's a couple of examples of how to do this for APEX & ORDS:

https://blogs.oracle.com/apex/post/custom-authentication-and-authorization-using-built-in-apex-access-control-a-how-to

https://oracle-base.com/articles/misc/oracle-rest-data-services-ords-custom-authentication-schemes

Note that both MD5 and SHA1 hashes are considered insecure these days; you'll want to use bcrypt to do the hashing. I don't know of a way to do this built-in to the database - you can create a Java stored procedure to do this.

As an alternative you may want to consider adding social authentication schemes (e.g. Google, FB, ...) in APEX instead (assuming this is appropriate of course).

https://docs.oracle.com/en/database/oracle/application-express/21.2/aeadm/editing-social-sign-in.html#GUID-693A8416-F42B-4907-8ED3-F4351CDD06AF

Rating

  (2 ratings)

Is this answer out of date? If it is, please let us know via a Comment

Comments

Check DB password from within database

Jonathan Taylor, December 09, 2021 - 6:16 pm UTC

Carlos seemed to want a way to check the database password from within the database itself.

We have used a version of the technique shown at http://daust.blogspot.com/2006/09/apex-database-authentication.html

It is a PL/SQL function that calls a Java procedure to make a connection to the same database (connection details of local password have to be passed) - and returns TRUE/FALSE.

To make it work on later versions of Oracle, the JDBC connection string needs changing:-

DriverManager.getConnection("jdbc:oracle:thin:@" + pServerName + ":" + pListenerPort + ":" + pSID, pUserName, pPassword);

The ":" + pSID needs changing to "/" + pServiceName

The server name and service name can be passed in as values of SYS_CONTEXT('USERENV','SERVER_HOST') and SYS_CONTEXT('USERENV','SERVICE_NAME'), but I think the listener port would need to be held in a parameter table to pass in.
Chris Saxon
December 09, 2021 - 6:26 pm UTC

Ah yes - thanks for sharing.

I still think having double authentication is a bad idea - having two copies of the password (however they're managed) just increases risk and complexity.

APEX to APEX

Recursion, December 13, 2021 - 7:24 am UTC

Create an APEX web service with database authentication. Call it from pl/sql with username/password.

More to Explore

APEX

Keep your APEX skills fresh by attending their regular Office Hours sessions.