10101010101001

0101010101001

Apex ntlm authentication using mod_ntlm and Microsoft Active Directory

with 6 comments

My first post is dedicated to Apex single sign on using mod_ntlm and Microsoft Active Directory.
We’ll be using mod_ntlm and dbms_ldap to achive true apex sso (single sign on).

Brief explanation of what is Active Directory (skip if you’re already familiar)

I will provide a brief explanation of what Active Directory before we proceed any further as it essential for a clear picture.

What is Active Directory?

Looking at the image above carefully you can see that Active Directory is a network protocol that provides an organization with a mechanism by which it can organize it’s people into sub-organizations or organization units (OU). Each organization unit can have users, computers, groups, printers in it. Just like an OU a group is another sub-organization only that is smaller than an OU.
Why all this need to organize?
Imagine that you have a huge pharmaceutical company that has a lot of computers, printers and computer-users all in a huge-network.
If you look at your company you’ll see that you have a lot of jobs like network administrators, the human resources staff, the accounting staff, the research staff, etc… Each of these people has certain responsibilities and restrictions of what they can and they can’t do with their computer. To give you a simple example: you don’t want the human resources staff have access to the latest information on the drug you are developing. Active directory would allow to have a server that would communicate in the background with all the computers establishing windows policies that restrict users to what network resources they might access.

But that’s not the only thing that Active Directory can do. It can also help you associate information with an entity (user/group/OU/workgroup/etc). For example you could associate for each user within your organization a phone number, a physical location, a name, an email and all these would be stored on an Active Directory server. Having this information and using a tool that searches Active Directory Server it’s easy to locate employees and communicate both for you and for the employees between themselves.

How’s all this information stored?
Active directory was designed to be very generic so it works with entities. An entity is a set of related information (set of attributes).
For example a user entity could be these pieces of information (name,email, phone). So an actual user entity would be (john doe, john.doe@company.com,+44123456). Being so generic how do you know that (john doe,john.doe@company.com,+44123456) is a user entity and not some other kind of entity? You could have an attribute called ‘objectClass’ for each entity. So our user would become (class,name,email, phone) and a real example would be (user, john doe,john.doe@company.com,+44123456), another example would be (user, fernando sucre ,fsucre@company.com,+4499999) and presuming that you also have a group entity (class, name) a group example would be (group,cancer research group) and presuming that you also have an organization unit (class, name) an example would be (organization unit, research unit).
You could imagine that all these entities are saved in some kind of database on the Active Directory Server which could be a computer running windows server 2008.

In practice the things are more complicated but the abstraction above will suit our needs.
If you would be to install Active Directory on a windows server 2008 it would provide you with pre-made entities like user, group, organization unit, etc. Each of these entities would have a set of default attributes like the ones in the examples above so you don’t really need to make custom entities unless you want to.
Enough Active Directory. Let’s move on.

Brief Overview of what we’re trying to do:

Let’s say you have two active directory groups. A power user group and a normal group. Each group can have users and other subgroups in it. You want to allow access only to users in these two groups (and all subgroups in them). Also you want certain apex pages to be accessed only by users from the power user group and not the ones from the normal group.

Solution Overview:
NTLM Authentication
Legend:
Client = Web Browser used to display apex pages
Server = Server where apex is installed
Domain Controller = Active Directory Server

Let’s split the problem in 2 pieces: User navigates in his browser to a page from the apex web-site.
What we want to do when he reaches a page is to detect on our server:
a) the user’s active directory identity
b) having the the user’s active directory identity we want to know if the user is in any of the two groups that are permitted in the application
if he’s not we want to redirect him to an error page
c) Knowing that the user is either a normal user, or a power user we check too see what kind of users does the page allow
if he’s a power user he can see every page
if he’s a normal user and the page can only be seen by power users then show him an error message, else show him the page

And now let’s solve a)
Apex is pretty much limited in this way because it does even know how to check whether the user is from our domain or not. But fortunately we can do that using an apache module called “mod_ntlm”. In our case you can think of the module as a library that is executed each time a page is requested on our Apex Server and that will check if the user is from our domain or not before the page is displayed. I won’t get into the details of how to install and configure “mod_ntlm” as there are some really good resources on that. See how to install and configure mod_ntlm.
It would be nice if we could configure “mod_ntlm” to restrict access only to users in the two groups we want but it doesn’t support that. So installing mod_ntlm will solve part “a)” of our problem.

And now let’s solve b)
mod_ntlm gives us the following: The user’s NETBIOSNAME\SAMACCOUNTNAME if the user is from our domain or null otherwise. (When I say user I mean the client who requested the page) Having that we must write a pl/sql function that will check if mod_ntlm didn’t return null and to check if the user is from the power group or the normal users group or neither. This function must execute before any page level events so even before the “Before Header” events. So where do we place it then?
Go to Shared Components -> Authentication
Create a new Authentication Scheme with these parameters:
Name : NTLM Page Session Management ->
Page Sentry Function: RETURN my_auth.modNtlmPageSentry
Login Processing -> Authentication Function: -BUILTIN-
Logout URL -> Logout URL: wwv_flow_custom_auth_std.logout?p_this_flow=&FLOW_ID&p_next_flow_page_sess=&FLOW_ID:ERROR_PAGE:&SESSION
Make this scheme current.

As you can see in the steps above the function will be called modNtlmPageSentry and will be in the my_auth package. You also need to make an error page and create an alias ERROR_PAGE for it. The my_auth package contains both modNtlmPageSentry and a lot of other helper functions that use the dbms_ldap package (written by oracle) to perform active directory queries in order to verify group membership. You can modify modNtlmPageSentry from point a) (See how to install and configure mod_ntlm.) to verify if your user belongs to an accepted group and if it does, allow him to view the page, otherwise deny it.

I leave these steps to you, as an exercise, because it’s not something difficult (3-5 mandays to be safe) and unfortunately I cannot provide you with the code:

Things you should consider when writing them:

-I realized some while ago that you might be vulnerable to ldap injection if mod_ntlm doesn’t sanitize it’s input. This is something you should double-check it exists in the mod_ntlm implementation. I’m guessing this sanitization is probably there, but I haven’t checked.

-Be careful where where you modify modNtlmPageSentry. If you do the group membership check calls in the wrong place, they will be called many times instead of once running you into strange errors.

-I used the bt.sql as described in an oracle magazine article, to format exceptions that are logged and the exceptions that are shown to the end user.

I won’t cover part c) because it is the easiest of the three and this blog post is already pretty huge.

Happy coding.

Advertisements

Written by Liviu Trifoi

January 29, 2009 at 6:09 pm

6 Responses

Subscribe to comments with RSS.

  1. Hi

    Where can I get the apex_ntlm_authentication_xmldb.zip

    Thanks,
    Shay

    Shay

    December 3, 2009 at 1:26 pm

    • With a smile to melt a thousand hearts

      January 19, 2010 at 8:48 am

      • Hello,
        Very thanks for this great manual!
        But unfortunately links to rapidshare are not working. You gave link to XML version, please give also good link to HTML DB version.
        Thanks.
        Mike

        mike

        March 31, 2010 at 6:57 pm

      • There’s little difference between the versions.
        To have the htmldb version all you need to do is uncomment this line in my_auth.sql:

        –FUNCTION modNtlmPageSentry(pApexUser IN VARCHAR2 DEFAULT ‘HTMLDB_PUBLIC_USER’)

        and comment this one
        FUNCTION modNtlmPageSentry(pApexUser IN VARCHAR2 DEFAULT ‘APEX_PUBLIC_USER’)

        Liviu Trifoi

        May 3, 2010 at 6:14 pm

  2. Thank you for the great explanation! Have you come across a good method to leverage the NTLM handshake to get the domain/username transparently behind the scenes? I would think that there would be some sort of ActiveX solution for this, but can’t seem to find one.

    What I’m trying to achieve is getting the username for the user logged into the machine on the domain in a secure way. I know I can hack the NTLM handshake to fake this process, but that is not a solution nor a real option, IMHO.

    John

    April 29, 2010 at 5:58 pm


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: