Do you remember the requirements for secure passwords?
• We need an algorithm, which takes some time to calculate to prevent from brute force
attacks (or at least to reduce its chance to success). JdbcRealm allows to determine the
algorithm.
• We need to add a salt to every password to protect against rainbow tables. JdbcRealm
fails on this requirement.Authentication and Authorization

Here, a custom realm comes into play. It enables the developer to save the passwords in any
store with any algorithm of his choice. Such a custom realm might be vendor specific. The
following realm is developed for the GlassFish server. Please check, whether it is applicable
to your server.
First of all, we need to derive a custom realm from AppservRealm .

public class AlumniRealm extends AppservRealm {

@Override
 public String getAuthType() {
 return "alumniRealm";
 }

@Override
 public String getJAASContext() {
 return "alumniRealm";
 }

@Override
 public Enumeration getGroupNames(String username) {
 List<String> groups = new ArrayList<>();
 groups.add("member");
 groups.add("admin");
 return Collections.enumeration(groups);
 }

}

We need to override three methods. For AuthType and JAASContext this realm simply
returns its name. This is needed to identify this realm within the server’s configuration.
The intention of GroupNames is to provide all possible groups of the solution. For simplicity of this demonstration, all the names are coded within the method. This might be ok for an authentication realm which is used for a certain application. Even better, you might define the group names within some properties or get it from a database.
Next, we need a LoginModule which need to be derived from AppservPasswordLoginModule.

public class LoginModule extends AppservPasswordLoginModule {

@Override
 protected void authenticateUser() throws LoginException {
 if (!(_currentRealm instanceof AlumniRealm)) {
 throw new LoginException("Unexpected realm: "
 + _currentRealm.getClass().getSimpleName());
 }

String[] groups = obtainPermittedGroups(_username, _passwd);
 if (groups.length > 0) {
 commitUserAuthentication(groups);
 }
 }

private static final String BASE_URI = "http://localhost:8082/AlumniAccount/api";

String[] obtainPermittedGroups(String userName, char[] passwd) {
 Client client = ClientBuilder.newClient();
 WebTarget resource = client.target(BASE_URI)
 .path("Accounts")
 .path("login")
 .path(userName)
 .path(new String(passwd));
 String groups = resource.request(MediaType.APPLICATION_JSON).get(String.class);
 client.close();
 return groups.split(";");
 }

}

Within the login module we first check whether the current realm is the expected custom
realm. _currentRealm (with a leading underscore like I do within my book) is a field within the parent method. If it is not of the expected type, we throw an exception.

In line 10 we call the method which returns an array of permitted group names. If the
authentication fails, this method does not return any group name. Otherwise we call
commitUserAuthentication by passing in this array.

Within obtainPermittedGroups we need to check the user credentials and to determine the
permitted groups.

Ensure your GlassFish server is down and add this to your domain’s login.conf file:

alumniRealm {
 de.muellerbruehl.alumnirealm.LoginModule required;
};

Within the same folder, edit the domain.xml file too.
Here you need to add the authentication realm within the <security-service> tag.

...
 <security-service>
 <auth-realm classname="de.muellerbruehl.alumnirealm.AlumniRealm" 
 name="alumniRealm"></auth-realm>
 ...
 </security-service>
...

You may add this realm after booting your server at the admin console.

Edit your web.xml file to use the new realm.

 <realm-name>alumniRealm</realm-name>

Have fun and stay tuned!

(This article is a shortened excerpt of the chapter Authenticate of my book. JASPIC and the new security RI Soteria will be matter of an other chapter.)