Inside Oracle APEX by Patrick Wolf

Using Windows Login Credentials for Single Sign On (NTLM authentication)

Most users are lacy and don't want to enter login credentials each time they start up an Oracle APEX application. They tell you,
"Hey I have already logged in into my computer, can't you use that information for the APEX application?".

Sure we can! The NTLM protocol is one way to do that.

Instructions on how to integrate mod_ntlm have been around for quite some time. See the article on HTMLDB Studio and a more up-to-date version by Martin Köb of GreenIT. But that always involves installing mod_ntlm on your Apache.

Jason Straub, a member of the Oracle APEX development team did some digging and found a PL/SQL only solution which doesn't require mod_ntlm. Have a look at his first blog posting called "NTLM HTTP Authentication and Application Express" and welcome him as new member of the Oracle APEX blogging community!

Jason, welcome and keep blogging such great articles!

Labels: , ,


« ... Read full posting ... »

Warning: DBMS_LDAP.simple_bind_s/APEX_LDAP.authenticate and NULL password

Just came across a very strange behavior of the DBMS_LDAP.simple_bind_s and APEX_LDAP.authenticate procedure which I used to do a basic LDAP authentication against our MS Active Directory server.

I used the following simple test code
DECLARE
vSession DBMS_LDAP.session;
vResult PLS_INTEGER;
BEGIN
DBMS_LDAP.use_exception := TRUE;
vSession := DBMS_LDAP.init
( hostname => 'your-active-directory-server'
, portnum => 389
);
vResult := DBMS_LDAP.simple_bind_s
( ld => vSession
, dn => 'CN=Wolf Patrick,[...rest of the DN...],DC=sphinx,DC=co,DC=at'
, passwd => 'x'
);
DBMS_Output.put_line('User authenticated!');
vResult := DBMS_LDAP.unbind_s(vSession);
END;
which raised the expected error

ORA-31202: DBMS_LDAP: LDAP client/server error: Invalid credentials. 80090308:
LdapErr: DSID-0C090334, comment: AcceptSecurityContext error, data 52e, vece
because of the wrong password. But as soon as I set NULL for the passwd parameter I got the "User authenticated!" message!!!
Couldn't believe that, so I also tried the APEX_LDAP wrapper package. Shows the same behavior with the following code!
BEGIN
IF APEX_LDAP.authenticate
( p_username => 'Wolf Patrick'
, p_password => NULL
, p_search_base => '[...rest of the DN...],DC=sphinx,DC=co,DC=at'
, p_host => 'your-active-directory-server'
, p_port => 389
)
THEN
DBMS_Output.put_line('ok');
ELSE
DBMS_Output.put_line('not ok');
END IF;
END;
So I did a final test with the built-in LDAP authentication scheme of Oracle APEX. The good news is that it captures this case and you are not able to login. So it looks like they are doing an extra check for a NULL password there.

But what does that mean?!?

  1. I'm a total moron and did something completely wrong. In that case please let me know!
  2. Our MS Active Directory server is set up wrong to accept NULL passwords for LDAP connections.
  3. MS Active Directory is a total piece of crap to accept NULL passwords. (BTW, I don't know if other LDAP servers like Oracle OID show the same behavior)
  4. All applications which are using APEX_LDAP.authenticate or DBMS_LDAP.simple_bind_s in a custom authentication scheme have a huge security flaw in them.
Can someone test the above code against his MS Active Directory or some other LDAP server and let me know?

BTW, in my opinion APEX_LDAP.authenticate should behave the same as the built-in LDAP authentication scheme and return FALSE.

Update as of 13-Jan-2008: John Scott pointed into the right direction. DBMS_LDAP.simple_bind_s has to accept a NULL password, because this function is also used to authenticate against a LDAP server if you want to do an anonymous search in the LDAP directory. I think it wasn't the best decision by the authors of the RFC 4513 to reuse the password parameter to decide if it's an anonymous bind or not. An extra parameter would have been much better an clearer. Anyway, we have to deal with that problem now.

If you directly use DBMS_LDAP.simple_bind_s for authentication in your code, don't forget to do a password IS NOT NULL check. If you use APEX_LDAP.authenticate you have to do the same.

But I have good news! APEX_LDAP.authenticate will be fixed in Oracle APEX 3.1 to include this check. Thanks to the APEX team!

Labels: , , ,


« ... Read full posting ... »

Adding a CAPTCHA to your Oracle APEX application

Haven't had the requirement to add one in my applications until now, but after reading Dan's posting about integrating reCAPTCHA with Oracle SSO, I thought that shouldn't be to hard to integrate into an Oracle Application Express (APEX) application too! A nice challenge for the evening ;-)

I know that there are some similar solutions out there on the OTN forum and on the unOfficial Wiki page, but the SVG solution isn't very secure in my opinion and the other solution uses an unsupported non-public package of Oracle APEX. So how can we integrate the reCAPTCHA widget instead?

Just follow my step by step instruction and you are done in minutes!
  1. Sign up at reCAPTCHA to get the private and public key.
  2. Load the stored function into your application schema which you can find at the end of the article.
  3. Go to the page where you want to integrate the CAPTCHA
  4. Create three page items
    • Name: P<your page>_RECAPTCHA_CHALLENGE_FIELD, P<your page>_RECAPTCHA_RESPONSE_FIELD and P<your page>_RECAPTCHA_ERROR
    • Type: Hidden
    • Sequence: Should be before all other items
    • Item Source: Always Null
  5. Put the following JavaScript code into the "Post Element Text" property of an existing page item or create a new region of type "HTML". Replace P7 by your own page number and also replace "your_public_key" with your public key you got during the registration.
    <script type="text/javascript"
    src="http://api.recaptcha.net/challenge?k=your_public_key&error=&P7_RECAPTCHA_ERROR.">
    </script>
    <script type="text/javascript">
    function renameRecaptchaField(pRecaptchaFieldName, pApexFieldName)
    {
    var vRecaptchaField = $x(pRecaptchaFieldName);
    var vApexField = $x(pApexFieldName);
    // Set for the dynamically generated Recaptcha field the same name as for
    // our APEX field (eg. t02), so that wwv_flow.accept puts the value into the APEX field.
    // After that remove the APEX field, because wwv_flow.accept can't handle
    // two fields with the same name.
    vRecaptchaField.name = vApexField.name;
    vApexField.parentNode.removeChild(vApexField);
    };
    renameRecaptchaField('recaptcha_challenge_field', 'P7_RECAPTCHA_CHALLENGE_FIELD');
    renameRecaptchaField('recaptcha_response_field', 'P7_RECAPTCHA_RESPONSE_FIELD' );
    </script>
  6. Create a page level validation
    • Type: PL/SQL - Function Returning Boolean
    • Sequence: 1
    • Validation Name: Recaptcha Check
    • Error Display Location: Inline in Notification
    • Validation:
      BEGIN
      :P7_RECAPTCHA_ERROR := checkRecaptcha
      ( pPrivateKey => 'your_private_key'
      , pChallenge => :P7_RECAPTCHA_CHALLENGE_FIELD
      , pResponse => :P7_RECAPTCHA_RESPONSE_FIELD
      );
      RETURN (:P7_RECAPTCHA_ERROR IS NULL);
      END;
    • Error Message: Recapture verification failed!

That's all, you are done!

So what was the challenge?

The JavaScript code provided by reCAPTURE creates two new fields on the fly. But because they do not comply with the names of the wwv_flow.accept package, which is called when a page is submitted, you will get an error during submit. So I had to use a trick. The nice side effect was that I can use the regular referencing in Oracle APEX, because they are just normal page items. See the comment text of the JavaScript code for details.

And here comes the stored function:

CREATE OR REPLACE FUNCTION checkRecaptcha
( pPrivateKey IN VARCHAR2
, pRemoteIP IN VARCHAR2 := OWA_Util.get_cgi_env('REMOTE_ADDR')
, pChallenge IN VARCHAR2
, pResponse IN VARCHAR2
)
RETURN VARCHAR2
IS
--
vRequest Utl_Http.req;
vPostText VARCHAR2(500);
vResponse Utl_Http.resp;
vResponseText VARCHAR2(2000);
vError VARCHAR2(200);
BEGIN
----------------------------------------------------------------------------
-- Build text for the post action.
-- For a field description, see
-- http://recaptcha.net/apidocs/captcha/
----------------------------------------------------------------------------
vPostText :=
'privatekey='||Utl_Url.escape(pPrivateKey, TRUE)||CHR(38)||
'remoteip=' ||Utl_Url.escape(pRemoteIP, TRUE)||CHR(38)||
'challenge=' ||Utl_Url.escape(pChallenge, TRUE)||CHR(38)||
'response=' ||Utl_Url.escape(pResponse, TRUE)||CHR(38);
----------------------------------------------------------------------------
-- if you need to set a proxy, uncomment next line.
----------------------------------------------------------------------------
/* Utl_Http.set_proxy('proxy.it.my-company.com', 'my-company.com'); */
----------------------------------------------------------------------------
-- Send data to reCAPTCHA.
----------------------------------------------------------------------------
vRequest := Utl_Http.begin_request
( url => 'http://api-verify.recaptcha.net/verify'
, method => 'POST'
);
Utl_Http.set_header
( r => vRequest
, name => 'Content-Type'
, value => 'application/x-www-form-urlencoded'
);
Utl_Http.set_header
( r => vRequest
, name => 'Content-Length'
, value => LENGTH(vPostText)
);
Utl_Http.write_text
( r => vRequest
, data => vPostText
);
vResponse := Utl_Http.get_response(vRequest);
IF vResponse.status_code = '200' -- the HTTP call was successful
THEN
Utl_Http.read_text(vResponse, vResponseText);
-- Has the user entered a correct solution?
IF vResponseText LIKE 'false%'
THEN
vError := SUBSTR(vResponseText, 7);
END IF;
ELSE
vError := 'HTTP status: '||vResponse.status_code||'-'||vResponse.reason_phrase;
END IF;
--
Utl_Http.end_response(vResponse);
--
RETURN vError;
END checkRecaptcha;


Labels: ,


« ... Read full posting ... »

Oracle APEX related articles you should read

Lately a few Oracle APEX related articles have been published which you should read.

Labels: , , ,


« ... Read full posting ... »

Hacking and hardening Oracle XE

Just read Pete Finnigan's Oracle security blog where he is pointing to the very interesting presentation Hacking and Hardening Oracle Express Edition done by Red Database Security at the UKOUG 2006.

Everybody who is deploying his APEX application on Oracle XE should read that!

Labels: ,


« ... Read full posting ... »

Best of Oracle Security 2006

Just read a very interesting paper titled Best of Oracle Security 2006, which was brought to my attention by Pete Finnigan's Oracle security weblog. It covers fixed security problems in Oracle DB, mod_plsql, APEX, ... which you/or your DBA may should know of.

Too bad for the english speaking readers, it's just available in german.

Labels: , ,


« ... Read full posting ... »