J2EE is not very good at that. However, I did this in the application. I have a user table in the database (only) used by my application, and I declared a scope in the context.xml file in the META-INF webapp directory (I use tomcat btw):
<Realm className="org.apache.catalina.realm.DataSourceRealm" dataSourceName="jdbc/fantastico" debug="99" localDataSource="true" digest="MD5" roleNameCol="ROLE" userCredCol="PASSWORD" userNameCol="USERNAME" userRoleTable="user_roles" userTable="active_users"/>
the data source is the same as that used in the rest of the application and is declared in the server.xml file of the tomcat installation (so that I can point to another db without changing the .war file).
I protected the places with roles in the web.xml file, making sure that I had the registration page and the login page:
<security-constraint> <display-name>Administrators</display-name> <web-resource-collection> <web-resource-name>admin</web-resource-name> <description>Admin</description> <url-pattern>/admin</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>Allow access only to administrators</description> <role-name>admin</role-name> </auth-constraint> </security-constraint>
I specified the <login-config> section with FORM as the auth method:
<login-config> <auth-method>FORM</auth-method> <realm-name/> <form-login-config> <form-login-page>/login/</form-login-page> <form-error-page>/login/error</form-error-page> </form-login-config> </login-config>
Since the scope is declared as using the MD5 digest, this is the MD5 password that must be stored in the database:
private static final char HEX[] = "0123456789abcdef".toCharArray(); public static String hex(byte data[]) { char[] chars = new char[2*data.length]; for (int i=0; i < data.length; i++) { int low = data[i] & 0x0f; int high = (data[i] & 0xf0) >> 4; chars[i*2] = HEX[high]; chars[i*2 + 1] = HEX[low]; } return new String(chars); } public static byte[] hash(byte data[]) { synchronized (DIGEST) { DIGEST.reset(); return DIGEST.digest(data); } } public static String hash(String value) { try { byte data[] = hash(value.getBytes("UTF-8")); return hex(data); } catch (UnsupportedEncodingException e) {
In the login form, this tomcat will be displayed whenever authentication is required, I added a link to the registration form:
...
<form id="login-form" action="j_security_check" method="post"> <table> <tbody> <tr> <td><label for="username">User name: </label></td> <td><input type="text" name="j_username" id="username" /></td> </tr> <tr> <td><label for="password">Password: </label></td> <td><input type="password" name="j_password" id="password" /></td> </tr> <tr> <td> </td> <td><input type="submit" id="submit" name="submit" value="Login"></td> </tr> <tr> <td> </td> <td><a href="../reg/create">I'm a new user</a></td> </tr> </tbody> </table> </form>
...
Now that the registration form has been submitted, I store the user in the database and I submit the redirection for the user to automatically log in:
...
response.sendRedirect(request.getContextPath() + "/j_security_check?j_username=" + URLEncoder.encode(getEmail(), "UTF-8") + "&j_password=" + URLEncoder.encode(password, "UTF-8"));
...
Hope this helps