Wednesday Oct 03, 2007

Mort Learns JDBC Realm Authentication for GlassFish

Here is another good blog on this subject.

In my last blog I showed you how to make a jdbc-resource that you can use for accessing a database.

Now I'll explain how to use that jdbc-resource to setup JDBC Realm Authentication and Authorization.

Realm Background

The job of a realm is to maintain a repository of user information.  Each user has one password and 0 or more groups that he belongs to.

At runtime a Realm is initially given a username and password and the realm then figures out if the user is authentic by checking the password.  It checks for authorization by seeing if the user's list of groups is authorized to use a resource (more on this later).

How to Create The Realm for userauth 

Using Admin GUI navigate to Configuration/Security/Realms.  Press the "new" button


Pick the classname that ends in JDBCRealm.  Use the jndi name of your jdbc-resource -- if it isn't userauth.

I'm assuming that you are starting from scratch with no user database.  If you already have such a database, you need to make sure your database table and column names are entered correctly and that your tables correspond to what JDBCRealm needs.  Such details are coming up...

Tip: Use the names in the screen-shot for the 2 table names and 3 column names.  These names are as good as the next.  If you standardize on these names you can use some tools I've developed for help administering and testing the realm.

Database user and password -- I'm not so sure about this.  The connection you get from the jndi name already has the username and password for that database.  I put the username and password from my database here and everything worked fine...

Digest Algorithm

You have to decide whether to save passwords as clear-text or encrypted.  If you want clear-text, leave the edit field blank.  If you want your passwords encrypted set this field to MD5.

My recommendation is to use MD5 for the passwords.  I have some tools with the code you need to convert a plain text password to an encrypted string in the right format for JDBCRealm.

On the other hand you can set it to no encryption -- and it will be much easier to seed the tables with test user info.   You can always change it to MD5 later when you have everything working.


All of the GlassFish administration work is now done.

Now you need to add some tables to your database.  You can run this sql script and it will do all the work for you.  The script also adds one user with username=admin and password=admin. 

The easy way to do this is to run "ij" -- a javaDB  sql console -- there is a copy here: <gf>/javadb/bin

ij> connect 'jdbc:derby://localhost:1527/userauth;user=APP;password=APP;create=true';

ij> run 'createdb.sql';

 

Now it's time to try out a protected web module.   What we want here is the World's Simplest Web Module.
In NetBeans, create a new web module.  The web module consists of one hello world jsp file.  Perfect.  If you don't use NetBeans then create some sort of ultra simple web module.

We have to add quite a bit of stuff to web.xml.  Netbeans makes fast work of it:

 

Here are the additions to web.xml (generated by NetBeans)

<security-constraint>
        <display-name>Constraint1</display-name>
        <web-resource-collection>
            <web-resource-name>protected</web-resource-name>
            <description/>
            <url-pattern>/\*</url-pattern>
            <http-method>GET</http-method>
            <http-method>POST</http-method>
            <http-method>HEAD</http-method>
            <http-method>PUT</http-method>
            <http-method>OPTIONS</http-method>
            <http-method>TRACE</http-method>
            <http-method>DELETE</http-method>
        </web-resource-collection>
        <auth-constraint>
            <description/>
            <role-name>ADMINISTRATORS</role-name>
            </auth-constraint>
        </security-constraint>
    <login-config>
        <auth-method>BASIC</auth-method>
        <realm-name>userauth</realm-name>
        </login-config>
    <security-role>
        <description/>
        <role-name>USERS</role-name>
    </security-role>
    <security-role>
        <description/>
        <role-name>ADMINISTRATORS</role-name>
    </security-role>
    </web-app>

 

I have 2 roles named "ADMINISTRATORS" and "USERS".  I use these same names as the groupid values in the database table.  This makes the role-mapping a bit easier because you use the exact same name on both ends.

You must setup the roll-mapping in sun-web.xml  The easiest way to do it so directly edit the file and add these lines:

  <security-role-mapping>
    <role-name>USERS</role-name>
    <group-name>USERS</group-name>
  </security-role-mapping>
  <security-role-mapping>
    <role-name>ADMINISTRATORS</role-name>
    <group-name>ADMINISTRATORS</group-name>
  </security-role-mapping> 

 Build and deploy this web module and then run it.  It will ask you for authentication info.  If you enter "admin" "admin" you should be allowed in to see the jsp page.

If you enter the name and password for someone that does not belong to the group "ADMINISTRATORS" then you will get an access violation error.

If there is interest, I'll follow up with some tools you can use to add users dynamically and to manage the database itself.


 



 

Tuesday Oct 02, 2007

Mort Learns JDBC for Glassfish

 I was intrigued by a problem and I set about solving it.  I finally did solve it.  It was a long difficult trail, but now that I know how to  do it it seems fairly easy.

If you are interested in Glassfish, JDBC, authentication and/or realms then read on.

The Problem: 

I now have 3 home made web modules doing useful things.  They all have authorization and authentication using file-based authentication.  That works fine but what if I want to add a new user?  It means I have to get the information and then create the right command to get the information into the key-file.  Or I figure out how to call Glassfish and have it put the username and password in for me.  Also -- what if I want the user's email address?  I can't put it in the key-file.  What about deleting a user?  Uh-oh.  Sounds complicated.  Plus I'm going to have to have some other data storage for the other user info.  I might as well use a real database -- the database gives me an easy way to add/edit/delete users at runtime (allowing users to create their own account unattended).  The database solves the problem of where to put the extra user info as well.

The Solution: 

Switch to JDBC Realm Authentication

The Trail

 
Using JDBC and JavaDB in GlassFish is easy.  You can go from no DB at all to a formed DB ready for your first SQL commands in 10 minutes or less.

There are a few traps waiting along for the unwary and I'll reveal them along with some tips.

 JavaDB Essential Information

 JavaDB is based on Derby.  A JavaDB database appears as a directory.  The directory's name is the database name.  When JavaDB opens up a database, that's it -- no other JavaDB runtime is now allowed to connect to that database.  

Tip: If you have connection problems look in the directory where the database is supposed to be.  Is it there?

If you use an embedded JavaDB database then what happens is that GlassFish itself is the JavaDB runtime that has that database locked.  As a result you can NOT look at the database anywhere else like, e.g. a SQL command processor.  If you want to issue SQL commands that way, you have to take down GlassFish to be able to access the database.  That's a disadvantage.  The advantages are

  • it is super-secure since there are no ports open for accessing the database.  GlassFish is in charge of  security for accessing the database
  • It is simpler to setup than the networked client

 

 The other choice is using the Derby Network Server.  This is just the classic client server database setup.  Derby runs one network server instance which is the "owner" of the databases embedded into it.  You can work on this database via SQL tools while GlassFish is connected to it.  It's not as simple.  You have to separately start and stop the JavaDB server.  GlassFish makes this easy for you with an asadmin command.  asadmin takes care of all the details -- environmental variables, classpath, etc.

I recommend the Network client mode.  It's no big deal, it's just another command that you use before starting GlassFish.  I figured out a way to make it a service in Windows as well (perhaps a future blog?)

Note: You can easily change an embedded client or a network client back and forth.

asadmin start-database -- dbhome <path-to-database-parent-dir>

Here's the first trap.  You don't have to specify the --dbhome option but I highly recommend always using it. 

Short Primer on Where the Heck is My Database on Disk?!?

If you run a stand-alone java program that uses embedded JavaDB, and you tell it to open a database named "foo", it will look for a directory named "foo" in the directory you ran the program from.   If you start a networked server -- it's the same deal, it will look in the directory that you started the server in.  GlassFish determines the all-important location of your databases on disk as follows and in this order

  1. use the --dbhome path as the root of all the databases  Done!
  2. else look in the current directory if there is a file named "derby.log" then make the current directory the root.
  3. else use a standard location:  <gf>/databases

If you don't use the --dbhome option then you need to be aware of whether or not derby.log is in your current directory.

 Let's Get This JDBC Party Started Already

You need to create two items in Glassfish in order to access a database.

The first is a JDBC Connection Pool.

In the Admin GUI navigate to Resources/JDBC/Connection Pool

Set the easy stuff.  Note that "name" is the name of the pool.  This pool is for a network client.  The configuration is a bit different for embedded databases.  I have pictures at the end of this blog for the embedded case.

 


 

Here is the first page of mysterious properties.  If you are an experienced DB person you'll know what to do.  If you're like me you'll happily take the defaults.

 

 This is where all the action is.  You don't want to make any mistakes here.  Here is the default layout:


And here is what it should look like.

Note that DataSource has no value.

Tip: set connectionAttributes to ";create=true".  Now you can make GlassFish create the database for you! 

 

And here is the new Connection Pool.  Click on it and then press the ping button and the (empty) database will be created.


 The next step is to create a JDBC Resource.  Armed with this jndi name you can get a connection to the database at runtime.

Navigate to Resources/JDBC/JDBC Resources and press the "new" button. 


That's all.  Glassfish is ready to serve up database connections.  From a servlet this code will do the job:

            InitialContext ctx = new InitialContext();
            DataSource ds = (DataSource) ctx.lookup("jdbc/userauth");
            Connection connection = ds.getConnection();

About

ByronNevins

Search

Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today