Tuesday, February 21, 2006

Using a custom login module with JDev 10.1.3

There's been a lot of traffic on the JDeveloper Forum in the past few days about custom LoginModule's both inside of JDeveloper's embedded OC4J and in OC4J standalone. After trials and tribulations, I've got it working in both places, and wanted to share the "how to" with others, so here goes...

What is a LoginModule?

A LoginModule is a class specified in the Java security specification that can be used to authenticate users and to assign roles to those users. In my case, I have user/role information stored in a database, so neither of the two Oracle-supplied LoginModule configurations (file-based or LDAP-based) would work for me. So, using the information in this article by Frank Nimphius and Duncan Mills for guidance, I developed my own LoginModule that would use a stored procedure to authenticate against the database. Now, the "fun" stuff starts... how to get this working in the embedded OC4J that comes with JDeveloper 10.1.3?

JDeveloper 10.1.3 Configuration for Custom Login Modules

Please note to replace brackets [ and ] with less-than and greater-than symbols in the following examples

Basically, there's a few simple steps that need to be done:

  1. Package your login module up into a jar file. I'm not going to go into any details here, but it's pretty straightforward to use a deployment profile to create a jar file with your login module and all of its dependent classes.

  2. Put the jar file containing your login module into [jdeveloper_home_directory]/jdev/lib. I suppose it could be anywhere, but this is a pretty convenient place for it.

  3. Make sure the embedded oc4j is shut down (go to the "Run" menu, and use the terminate option to shut it down if it's running.

  4. The next thing to do is to ensure that your login module JAR file is visible to the embedded oc4j. The configuration files for the embedded oc4j are in [jdeveloper_home_directory]/jdev/system/oracle.j2ee.10.1.3.36.73/embedded-oc4j/config (at least for the current version as of the date I'm writing this). You need to add a line to the application.xml using your favorite text editor that looks like this:

    [library path="C:\o\jdev1013\jdev\lib\TestLogin.jar"/]

    (my login module was in a JAR called TestLogin.jar)

  5. The next thing to do is to tell the embedded OC4J to use a custom login module and dynamic roles. In the same application.xml, locate the line that looks like this:


    [jazn provider="XML"/]


    and replace it with this:

    [jazn provider="XML"]
    [property name="custom.loginmodule.provider" value="true"/]
    [property name="role.mapping.dynamic" value="true"/]
    [/jazn]


  6. The next thing you need to do is to configure the application to use a custom login module. This configuration is done in the system-jazn-data.xml file in the same directory. One thing to note is that the J2EE application name is ALWAYS "current-workspace-app" in the embedded OC4J. Here is the relevant section from my system-jazn-data.xml:


    [application]
    [name]current-workspace-app[/name]
    [login-modules]
    [login-module]
    [class]john.TestLogin[/class]
    [control-flag]required[/control-flag]
    [options]
    [option]
    [name]application_realm[/name]
    [value]test[/value]
    [/option]
    [option]
    [name]jdbcUrl[/name]
    [value]jdbc:oracle:thin:un/pw@localhost:1521:ORCL[/value]
    [/option]
    [/options]
    [/login-module]
    [/login-modules]
    [/application]


    Your login module may have other options, so configure as necessary. My custom LoginModule was "john.TestLogin" and had 2 options: jdbcUrl and application_realm

  7. Configure your application for security as per the J2EE spec. In my case, it was simply adding some stuff to web.xml for my project in JDev.


  8. That's it! Now when you run your application from within JDeveloper, it should prompt for a login (you can change the config to use a form instead of the default BASIC authentication)
OC4J Standalone and Oracle AS 10.1.3 Configuration

Fortunately, the configuration with OC4J standalone and Application Server 10.1.3 is much simpler. The enterprise manager deployment wizard actually has some screens to allow you to configure the login module. This process is documented pretty well, but here's a short synopsis:

  1. Make your login module JAR file available in the classpath. I did this by editing application.xml (in [oc4j_home]/j2ee/home/config) to include a [library] element (just like for the embedded configuration above.

  2. Deploy your application using the OC4J/AS enterprise manager. When you get to step 3, (Deployment Settings), look what you've got:










  3. Now, you can click to "Select Security Provider" and "Map Security Roles"
I hope this helps those who are struggling with this, as I was.

12 comments:

John Stegeman said...

Adrian,

You can access the user name from the servlet session context. If you're using JSF:

ctx = FacesContext.getCurrentInstance();
ectx = ctx.getExternalContext();

//Ask the container who the user logged in as
_userName = ectx.getRemoteUser();

Hope this helps.

Anonymous said...

Hi,

I have been trying to do something similar. I followed the sample in SRDemo but that doesn't use the data from the database schema. It is possible for you to share the example you have.

I would really appreciate that.

Thanks..

Anonymous said...

John,

I am experiencing the same error if I have the 'role.mapping.dynamic' set in orion-application.xml? Mind sharing how you addressed this issue?

Thanks,
Karthik

Anonymous said...

Oops, I am referring to your OTN thread..

http://forums.oracle.com/forums/thread.jspa?messageID=1207669�

I left you a message there as well!

I am experiencing the same error if I have the 'role.mapping.dynamic' set in orion-application.xml? Mind sharing how you addressed this issue?

Thanks,
Karthik

Anonymous said...

John,
Thanx for the descriptive guide, I have a strange problem with my custom login module (its quite the same as DBTableLM) that I thought you might be able to help.
I did all the things you and Frank blogged over 10 times with any combination of configurations you imagine, but still cant get my roles get read by the OC4J, I constantly get 403 Forbidden Error though the Login module works perfectly. Any idea of what the problem might be? have you done any special config for grantees in jazn policies? if so how? I'm under pressure to have it done asap, I'd be glad if you take it urgent, I'll check here for the answer.

Anonymous said...

I finally figured out what the problem was and thought the remedy may help some other poor guys getting stucked with the same issue, here is the case:
I was trying to use Frank's sample DBLoginModule, namely DBTableLM to handle security in my application, used John's guidlines to configure embedded oc4j but I couldn't have jazn properly recognize registered RolePrinciples in the subject to authorize the user.
The actual problem was with the Frank's LoginModule and what I did that solved the problem is as follow:
1. Chenged the order of registering principles, in the original code, it first registers the UserPrinciple and then the RolePrinciple, I just swaped the parts in code (dont ask me why, its near 3 weeks Im working on it)
2. In DBRolePricipal and DBUserPrincipal class definitions I had them to extend "serializable" interface
3. had the role names getting out of query results trim'd before instantiating pricipal objects in the code
That was all, the rest of configuration stuff are all that John and Frank has mentioned.

anybody need further details may contact me on: mehrdad dot fatemi at gmail dot com

Anonymous said...

plz give an example for authentication of a Html page's field value with corresponding schema's table value.

Anonymous said...

Hi..
I followed your steps for embedded server and Standalone server.
My application is runing good with DBSystemLoginModule on embedded server.
But it isn't run on standalone OC4J server.

I deploied my application using OEM. At step3, I chose customer for Security Provider, and then clicked add "login module" .
At "add login modelue" I put my DBSystemLoginModule's class,same as login module class in system-jazn-data.xml on embedded server.
And then I ran my application.
I got error.

In this case unable to find loginModule class.
Should I do something more for that?

Anonymous said...

Hi friend

your blog has been of great help to me as i could figure out the solution of my problem that had been suffocating till now.....thanks alot dude.

sriki79 said...

Thanks for the informative article. We are using the DBSystemLoginModule and able to authenticate the user. But we are facing a problem in reporting the exact errors(for example, if user account is expired, if the user account is locked..e.t.c)to the user through the jsp page. any exception from the DBSystemLoginModule is coming as 'null' to the front end. Any help on this will be appreciated.
Thanks.

Custom Papers Writing said...

Many institutions limit access to their online information. Making this information available will be an asset to all.

Send Flowers to France said...

Hey great stuff, thank you for sharing this useful information and i will let know my friends as well.