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.


 



 

Comments:

I am on a steep learning curve, ran samples on JBoss, Tomcat (5 and 6) and now GlassFish (bundled with Netbeans 6.0 Beta). Any chance of providing some guidance on how this can be done with Netbeans only, i.e. putting all the configuration in the web.xml file may be. I am new to a lot of things, hence the steep learning curve :(

Posted by George Mutale on October 11, 2007 at 02:09 AM PDT #

I didn't even know that there was 'something sitting on this port'
http://localhost:4848/asadmin

I am that new that almost all the questions I ask will sound silly. Now that I have access to the app server interface, I will try out the info. that you have provided on the page. Thanks.

Posted by George Mutale on October 11, 2007 at 02:26 AM PDT #

Excellent question. I found out that there is a non-GUI way to add resources. You create an xml file and then use the CLI (asadmin) to create the resources.
I've never done it. I will research it and blog about it if you leave another comment here requesting it.

Posted by Byron Nevins on October 11, 2007 at 08:00 AM PDT #

Thanks. That will be great. There seems to be so many ways of doing things and so many examples using different application servers and frameworks, :(

For now I am sticking with Hibernate, JSF, Netbeans and GlassFish.

Thanks for your help.

Posted by George Mutale on October 11, 2007 at 06:25 PM PDT #

Did you encounter any kind of login exception while doing this?

I have my web application correctly setup and using a file realm. Switching to a jdbc realm always gives me the following error:

Web login failed: Login failed: javax.security.auth.login.LoginException: Security Exception

Posted by Patrick Julien on November 28, 2007 at 01:57 AM PST #

Once I got it working -- I don't see any errors.

What did the log message in server.log say?
There is a bug in the Realm code -->If it gets a SQL Exception containing the precise problem description -- it throws away the Exception and gives you a useless generic message instead.
If you turn up the logging to FINE -- you will see these SQL errors.

Posted by guest on November 28, 2007 at 02:20 AM PST #

The log message says exactly that:

"Web login failed: Login failed: javax.security.auth.login.LoginException: Security Exception"

I am in the process of bumping the log level to fine for security. I can see that "doPasswordLogin" fails but I can a useless login exception, can't see anything about SQL still.

Posted by Patrick Julien on November 28, 2007 at 02:24 AM PST #

Have it, the problem seems to be that clear text passwords do not seem to work with glassfish 2.

Doing the exact same thing but setting MD5 for the digest algorithm finally worked.

Posted by Patrick Julien on November 28, 2007 at 02:37 AM PST #

I sort of suspected that the digests had something to do with your problem.

Glassfish WILL work with plaintext -- you leave the Digest Algorithm: field blank for the realm.

In fact -- you may want to do that in this scenario:

Sometimes you send in the digest of the password via a cookie without user intervention. Now what you want to do is MD5 digesting on the client side. Then you tell the server side that the passwords are plaintext.

-- byron

Posted by guest on November 28, 2007 at 02:56 AM PST #

What are necessary steps to setup programmatic login using jdbcrealm from scratch?

Posted by Arthur on December 16, 2007 at 02:30 AM PST #

Same problem: "JAAS authentication aborted.
SEC5046: Audit: Authentication refused for [valent].
doPasswordLogin fails
javax.security.auth.login.LoginException: Security Exception".

I don't use MD5. In DB the passwords is stored as plain text. I use Netbeans 6.

Posted by Vale on January 20, 2008 at 05:06 PM PST #

To Patrick Julien: It's because of there has to be 'none' keyword for plain-text passwords indtead of "nothing". Check out http://blogs.sun.com/swchan/entry/jdbcrealm_in_glassfish.
The 'none' keyword works for me with GlassFish v2.1-b11.

Posted by Petr Hadraba on February 19, 2008 at 01:17 AM PST #

If the authentication is used for a javaEE App-client, at the beginning, a default log-in dialogue is used. How can I use my custom log-in dialogue for authentication?

Posted by Hillol on September 08, 2008 at 07:22 PM PDT #

This has been great content and exactly what I have been looking for and racking my head against for days. I'm a new user webber and was wondering if there are any tutorials or help to add a logout to this. Session invalidate doesn't seem to work. Also any tricks to creating an registration form for this database?

Posted by Scott W on March 25, 2009 at 02:52 AM PDT #

To Scott W.

This should definitely log you out:

request.getSession().invalidate();

==========================

What do you mean by registration form? Try this and tell me if that is what you are interested in and I'll post the source code.

try it -- create an account...

http://www.bnevins.com/AuthAdmin/Registration

Posted by Byron Nevins on March 25, 2009 at 03:38 AM PDT #

thanks for the quick response!

request.getSession().invalidate();

isn't working for me on top of a logout page. It keeps the session logged in.

And yes a registration form like that is what I was referring to but I think I can figure that out, but that leads to another question,

How would you setup form login (so the user information is stored for the session) based around what you described above?

thanks again!

Posted by Scott W on March 25, 2009 at 05:09 AM PDT #

Hi,
I'm still a novice with Java and Glassfish. I'm using Netbeans 6.5 and I have an Enterprise Application that contains numerous Web Applications. I have successfully set up security for each of these web applications and I am in the process of creating another web application that acts as a "portal" for the entire enterprise app that will have hyperlinks to navigate to a selection of pages that are within the other web applications depending on the role of the user and whether they are allowed to visit those pages (the hyperlinks are rendered conditionally according to the user's role).

Each of the web applications are using the same realm, but whenever I log into the portal app, if I try to visit a page that is within one of the other web applications, I am still required to login again, I was hoping I would not have to since I already logged in to one application (the portal) using the same realm.

Posted by Brian M on April 17, 2009 at 03:17 AM PDT #

Sorry, accidentally posted before actually asking the question ;P

What I meant to ask is if it is possible to be able to visit any page in any web application under the same enterprise application without logging in multiple times if I use the same realm for each web application? Thanks in advance!

Posted by Brian M on April 17, 2009 at 03:20 AM PDT #

http://docs.sun.com/app/docs/doc/820-4496/beacq?a=view

Read the article on SSO (Single Sign On)

Posted by Byron Nevins on April 17, 2009 at 04:01 AM PDT #

Thanks Byron!

This works great, it does exactly what I was looking for, thanks again for your help and quick response, have a good one.

Posted by Brian M on April 17, 2009 at 04:58 AM PDT #

Thanks for this post - I'm just looking at using this to secure an app so very useful. The question I have is how can I pass back to the calling application the role/permissions which an authenticated user has been assigned?

In my particular case, I'm looking to deploy a Flex application on glassfish and but my app needs to know what permissions an authenticated user has. I can pass parameters into a Flex app via 'flashVars' but I don't know how to get the 'role-name' of a session.

Can this be obtained from the headers anyway?
Tks
Alex

p.s. this page from adobe shows how it can pick params up from a jsp request ..
http://livedocs.adobe.com/flex/3/html/help.html?content=passingarguments_3.html

Posted by Alex Curtis on May 05, 2009 at 08:48 PM PDT #

Thanks a lot. It was really helpful.

Posted by Raihan Kibria on May 17, 2009 at 12:20 AM PDT #

I like this tutorial very much. It is one way I am considering for authentication in a project I am working on. I can't seem to get it to work though. I follow the directions the way the instructions/pictures show and enter the code where I think it should be. When I run the simple program with the db given in the example it seems to find the database because it says that it requires authentication but when I put in the username and password from the example I get an HTTP 401 error or else it just keeps asking for the user information over and over. I am using Netbeans 6.5 and GF server v 2 oh, and JDBC. I even went to "none" where the MD5 digest was and reset the password to just "admin" but still no luck. Where am I going wrong? Thanks in advance for any suggestions.
JW

Posted by Joy Wells on August 06, 2009 at 11:52 AM PDT #

hi,
i got this Errors

SEC1112: Cannot validate user [admin] for JDBC realm.
SEC5046: Audit: Authentication refused for [admin].

if you have any Solution then please give me reply

thank you in Advance

Posted by singireddy on December 24, 2009 at 08:01 PM PST #

In your servlet or JSP, fetch the needed information, either from the request object, or directly from the database (you are using JDBCRealm after all, so you probably have db access) and then render this information in some way the Flex app understands to the flashVars parameter.

For example:

request.getUserPrincipal()

Will give you the username,

request.isUserInRole('roleName')

will return true or false depending on wheter the current user has the given role or not, and

String username = request.getPrincipal();
SELECT groupname FROM groups WHERE username = <username>

will give all the names of the groups the user is in.

The idea of Java EE security is that apps concern themselves only with roles users may have in that app, whereas the appserver deals with users and groups (together: realms). This way apps can be created independently from any used realms and authorization rules are created by mapping roles to groups or users. In Glassish this mapping us usually done in sun-web.xml.

The JDBCRealm is a way to bring the realm within reach of the app, so you can have a registration page where people can create an account for themselves for example. So the JDBCRealm tells the appserver how users and groups are defined in the db. If the app also knows this, it can create (and query) groups and roles directly on the db.

Posted by Stijn de Witt on May 06, 2010 at 08:05 AM PDT #

After struggling with JDBCRealm for some time i can give an incomplete list of gotcha's:

\* Digest: "" does not work, must be "none". (\*)
\* Digest: "none" was broken in older releases
\* To diagnose, set log level to FINEST for:
- com.sun.enterprise.security
- javax.enterprise.system.core.security
\* Even at FINEST level, many failure reasons will not be logged.
\* Encoding can be "" (empty)
\* If you specify Encoding, it will be used, even when Digest is set to "none"
\* Username column \*must\* have same name in both Users and Groups tables
\* String columns should be VARCHAR, not CHAR
\* Database User and Database may be empty, but will overrule that of the JDBC connection (the idea is that you can then leave them off the JDBC connection for added security, just leave them empty)
\* JAAS Context \*should\* be "jdbcRealm", or you should change the string in \\glassfish\\domains\\domain1\\config\\login.conf

(\*) Of course, better to use some digest algorithm, but MD5, the default, is already compromised, so better pick another.

Posted by Stijn de Witt on May 06, 2010 at 08:21 AM PDT #

Thanks for the comments Stijn! I hope it's all working for you.
I set the digest to MD5 on my personal web site and it works fine for me.

Posted by W Byron Nevins Jr on May 06, 2010 at 01:09 PM PDT #

Yes, it does work of course. And for your personal website, who cares whether it's vulnerable? :)

But digesting the password of users has a very specific reason. If some hacker were to gain access to the database and the passwords were not digested (not stored as some unreadable code, but instead in plaintext, so just "secret" etc), that hacker would immediately gain control of all accounts in the database. You basically would have to tell all your users that their accounts have been compromised and they need to change their passwords.

So digesting (a.k.a hashing) the passwords is definitely the way to go. But MD5 has been compromised recently and as the math gurus keep pounding on it, it is becoming more and more vulnerable, up to a point were it's essentially no longer useful:

"One of the infosec industry's top Web security gurus said a hash algorithm flaw, discovered more than a year ago, may well be the most dangerous security flaw on the Web."

MD5 hash vulnerability is expert's top Web security flaw
http://hackingexpose.blogspot.com/2010/03/md5-hash-vulnerability-is-experts-top.html

"In 1991 Rivest announced [..] MD5[..]. In 1993 some weaknesses in its design were pointed out, but it took until 2004 before collisions were found. Producing collisions is nowadays a matter of seconds on a PC."

MD5 considered harmful today
http://www.win.tue.nl/hashclash/rogue-ca/

What does that mean, "finding collisions"?

Basically a hashing or digestion algorithm takes a source string, such as our password, or even the whole contents of a book, and transforms it in a way that it yields a very specific, but random looking sequence of bits. That process is repeatable, so hashing the book 20 times will yield the same hash every time. This is used in digital signatures for example. If anyone changes a page of the book, that change can be detected, because hashing the changed version will yield a different hash. And also, because the entire book gets compressed down to just 160 bits (for MD5), it's impossible to reverse the process. Some information was just lost and can never be recovered. Authentication mechanisms such as that of Glassfish use this to keep passwords save from peeking by hashing them before storing them in the database.

Ok, so what about those collisions.

Because all information gets compressed to 160 bits, there is a huge, but not infinite, amount of different hashes. Some different source strings are bound to yield the same hash, sometimes. That is what we call collisions. As long as it's very difficult to guess such collisions, that's not a problem. But as the quote said, collisions can nowadays be produced within seconds. A lot of these collisions may not be viable (too long, containing illegal characters etc), but let's just say it takes an hour to find one that fits in the password box of the login page. This means that if a hacker knows the hashed version of the password of the 'admin' account, within an hour he will be able to find some string (probably different from the original password) that he can enter in the login page and that, once hashed, will yield the exact same hash as the original password. Glassfish will the accept that pasword as the original, because it has no way of seeing the difference. And \*bam\*, the hacker just got in.

As PC's get quicker, that hour will only get shorter, up to the point where you might as well not use a digest algorithm at all.

Bottom line: MD5 is compromised and hence \*not\* the right default to use for Glassfish. Especially since better, uncompromised algorithms are available out of the box and can be selected by just entering their name in the 'Digest' property of the realm configuration instead of the default 'MD5'. I suggest using SHA-256, but just check this document and take your pick:

Java ™ Cryptography Architecture
Standard Algorithm Name Documentation
http://java.sun.com/javase/6/docs/technotes/guides/security/StandardNames.html#MessageDigest

Posted by Stijn de Witt on May 07, 2010 at 05:25 AM PDT #

You said you will post another blog about how to add user dynamically. I wonder if you have done that yet? great post by the way. It works great

Posted by Thang Pham on July 22, 2010 at 03:59 AM PDT #

Hi Stijn de Witt
I can seem to get SHA-256 digest to work. So I have SHA-256 in the digest field. I write a simple Java code to print out a password field using SHA-256. I paste that hashed password into the password field in the database. But it not working. I notice that for the same string, every time I generated the hash. I got a new hash. Is that right? Below is how I hash

MessageDigest md = MessageDigest.getInstance("SHA-256");
String text = "admin";
md.update(text.getBytes("UTF-8"));
byte[] digest = md.digest();
System.out.println(digest.toString());

Posted by Thang Pham on August 09, 2010 at 06:50 AM PDT #

Hi All,

Everything i done in my application what the steps are explained.But after giving the login credentials "admin" and "admin", i am getting the same login screen again and again. It doesn't redirect to JSP page.

Anything i am missing to do?. Please help me.

Regards,
-Periyasamy

Posted by Periyasamy on February 09, 2011 at 03:15 PM PST #

Hi all,

The Basic authentication is working fine in my application. The problem was the datasource URL was not set the database. I set the database to URL.So this is working fine. Thanks:)

Then, I wish to change the authentication type as "DIGEST" in web.xml. And also i changed the JAAS context as "jdbcDigestRealm" in Realm properties. But after i run the application, i am getting the exception as "javax.security.auth.login.loginexception: login failure: all modules ignored".

Can anybody help me?. I want to use "Digest" based authentication using this example

Regards,
Periyasamy.

Posted by Periyasamy on February 09, 2011 at 06:31 PM PST #

Here is one post about jdbc security realm in glassfish.
http://jugojava.blogspot.com/2011/02/jdbc-security-realm-with-glassfish-and.html

Posted by Gordan on February 28, 2011 at 11:51 PM PST #

;lj

Posted by guest on December 06, 2011 at 03:55 AM PST #

Post a Comment:
  • HTML Syntax: NOT allowed
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