Methods Summary |
---|
private void | addGroupNames(java.lang.String[] groupList)Add group names to the groups table. It is assumed all entries are
valid group names.
if (groupList != null) {
for (int i=0; i < groupList.length; i++) {
Integer groupSize = (Integer)groupSizeMap.get(groupList[i]);
groupSizeMap.put(groupList[i],
(groupSize != null) ?
new Integer(groupSize.intValue() + 1): new Integer(1));
}
}
|
public synchronized void | addUser(java.lang.String name, java.lang.String password, java.lang.String[] groupList)Adds new user to file realm. User cannot exist already.
validateUserName(name);
validatePassword(password);
validateGroupList(groupList);
if (userTable.containsKey(name)) {
String msg = sm.getString("filerealm.dupuser", name);
throw new BadRealmException(msg);
}
addGroupNames(groupList);
FileRealmUser ud = createNewUser(name, password, groupList);
userTable.put(name, ud);
|
public java.lang.String[] | authenticate(java.lang.String user, java.lang.String password)Authenticates a user.
This method is invoked by the FileLoginModule in order to
authenticate a user in the file realm. The authentication decision
is kept within the realm class implementation in order to keep
the password cache in a single location with no public accessors,
to simplify future improvements.
FileRealmUser ud = (FileRealmUser)userTable.get(user);
if (ud == null) {
if (_logger.isLoggable(Level.FINE)) {
_logger.fine("No such user: [" + user + "]");
}
return null;
}
boolean ok = false;
try {
ok = SSHA.verify(ud.getSalt(), ud.getHash(), password.getBytes());
} catch (Exception e) {
_logger.fine("File authentication failed: "+e.toString());
return null;
}
if (!ok) {
if (_logger.isLoggable(Level.FINE)) {
_logger.fine("File authentication failed for: ["+user+"]");
}
return null;
}
String[] groups = ud.getGroups();
groups = addAssignGroups(groups);
return groups;
|
private void | changeGroups(java.lang.String[] oldGroupList, java.lang.String[] newGroupList)This method update the internal group list.
addGroupNames(newGroupList);
reduceGroups(oldGroupList);
|
private static FileRealmUser | createNewUser(java.lang.String name, java.lang.String pwd, java.lang.String[] groups)Produce a user with given data.
FileRealmUser ud = new FileRealmUser(name);
if (groups == null) {
groups = new String[0];
}
ud.setGroups(groups);
setPassword(ud, pwd);
return ud;
|
private static FileRealmUser | decodeUser(java.lang.String encodedLine, java.util.Map newGroupSizeMap)Decodes a line from the keyfile.
StringTokenizer st = new StringTokenizer(encodedLine, FIELD_SEP);
String user = null;
String pwdInfo = null;
String groupList = null;
try { // these must be present
user = st.nextToken();
pwdInfo = st.nextToken();
} catch (Exception e) {
String msg = sm.getString("filerealm.syntaxerror", encodedLine);
throw new IASSecurityException(msg);
}
if (st.hasMoreTokens()) { // groups are optional
groupList = st.nextToken();
}
byte[] hash = new byte[20];
byte[] salt = SSHA.decode(pwdInfo, hash);
FileRealmUser ud = new FileRealmUser(user);
ud.setHash(hash);
ud.setSalt(salt);
Vector membership = new Vector();
if (groupList != null) {
StringTokenizer gst = new StringTokenizer(groupList,
GROUP_SEP);
while (gst.hasMoreTokens()) {
String g = gst.nextToken();
membership.add(g);
Integer groupSize = (Integer)newGroupSizeMap.get(g);
newGroupSizeMap.put(g, (groupSize != null) ?
new Integer(groupSize.intValue() + 1) : new Integer(1));
}
}
ud.setGroups(membership);
return ud;
|
private static java.lang.String | encodeUser(java.lang.String name, FileRealmUser ud)Encodes one user entry containing info stored in FileRealmUser object.
StringBuffer sb = new StringBuffer();
String cryptPwd = null;
sb.append(name);
sb.append(FIELD_SEP);
String ssha = SSHA.encode(ud.getSalt(), ud.getHash());
sb.append(ssha);
sb.append(FIELD_SEP);
String[] groups = ud.getGroups();
if (groups != null) {
for (int grp = 0; grp < groups.length; grp++) {
if (grp > 0) {
sb.append(GROUP_SEP);
}
sb.append((String)groups[grp]);
}
}
sb.append("\n");
return sb.toString();
|
public java.lang.String | getAuthType()Returns a short (preferably less than fifteen characters) description
of the kind of authentication which is supported by this realm.
return AUTH_TYPE;
|
public java.util.Enumeration | getGroupNames()Returns names of all the groups in this particular realm.
Note that this will not return assign-groups.
return groupSizeMap.keys();
|
public java.util.Enumeration | getGroupNames(java.lang.String username)Returns the name of all the groups that this user belongs to.
FileRealmUser ud = (FileRealmUser)userTable.get(username);
if (ud == null) {
String msg = sm.getString("filerealm.nouser", username);
throw new NoSuchUserException(msg);
}
String[] groups = ud.getGroups();
groups = addAssignGroups(groups);
Vector v = new Vector();
if (groups != null) {
for (int i = 0; i < groups.length; i++) {
v.add(groups[i]);
}
}
return v.elements();
|
public com.sun.enterprise.security.auth.realm.User | getUser(java.lang.String name)Returns the information recorded about a particular named user.
FileRealmUser u = (FileRealmUser)userTable.get(name);
if (u == null) {
String msg = sm.getString("filerealm.nouser", name);
throw new NoSuchUserException(msg);
}
return u;
|
public java.util.Enumeration | getUserNames()Returns names of all the users in this particular realm.
return (new Vector(userTable.keySet())).elements(); // ugh
|
private static void | help()Show help for the test command line tool.
System.out.println("FileRealm -c <name <pwd [group]*");
System.out.println("FileRealm -v <pwd `output of -c`");
System.exit(1);
|
protected void | init(java.util.Properties props)Initialize a realm with some properties. This can be used
when instantiating realms from their descriptions. This
method is invoked from Realm during initialization.
super.init(props);
String file = props.getProperty(PARAM_KEYFILE);
if (file == null) {
String msg = sm.getString("filerealm.nofile");
throw new BadRealmException(msg);
}
this.setProperty(PARAM_KEYFILE, file);
String jaasCtx = props.getProperty(IASRealm.JAAS_CONTEXT_PARAM);
if (jaasCtx == null) {
String msg = sm.getString("filerealm.nomodule");
throw new BadRealmException(msg);
}
this.setProperty(IASRealm.JAAS_CONTEXT_PARAM, jaasCtx);
if (_logger.isLoggable(Level.FINE)) {
_logger.fine("FileRealm : "+PARAM_KEYFILE+"="+file);
_logger.fine("FileRealm : "+IASRealm.JAAS_CONTEXT_PARAM+"="+
jaasCtx);
}
loadKeyFile();
|
private static boolean | isValid(java.lang.String s, boolean userName)Return false if any char of the string is not alphanumeric or space
or other permitted character.
For a username it will allow an @ symbol. To allow for the case of type
username@foo.com. It will not allow the same symbol for a group name
for (int i=0; i<s.length(); i++) {
char c = s.charAt(i);
if (!Character.isLetterOrDigit(c) &&
!Character.isWhitespace(c) &&
MISC_VALID_CHARS.indexOf(c) == -1) {
if (userName && (c == '@")){
continue;
}
return false;
}
}
return true;
|
private void | loadKeyFile()Load keyfile from config and populate internal cache.
String file = this.getProperty(PARAM_KEYFILE);
_logger.fine("Reading file realm: "+file);
userTable = new Hashtable();
groupSizeMap = new Hashtable();
BufferedReader input = null;
try {
input = new BufferedReader(new FileReader(file));
while (input.ready()) {
String line = input.readLine();
if (!line.startsWith(COMMENT) &&
line.indexOf(FIELD_SEP) > 0) {
FileRealmUser ud = decodeUser(line, groupSizeMap);
userTable.put(ud.getName(), ud);
}
}
} catch (Exception e) {
_logger.log(Level.WARNING, "filerealm.readerror", e);
throw new BadRealmException(e.toString());
} finally {
if (input != null) {
try {
input.close();
} catch(Exception ex) {
}
}
}
|
public static void | main(java.lang.String[] args)Test method. Not for production use.
if (args.length==0) {
help();
}
try {
if ("-c".equals(args[0])) {
String[] groups=new String[0];
if (args.length>3) {
groups=new String[args.length-3];
for (int i=3; i<args.length; i++) {
groups[i-3]=args[i];
}
}
FileRealmUser ud = createNewUser(args[1], args[2], groups);
String out=encodeUser(args[1], ud);
System.out.println(out);
FileRealmUser u=decodeUser(out, new Hashtable());
System.out.println("verifies: "+
SSHA.verify(u.getSalt(), u.getHash(),
args[2].getBytes()));
} else if ("-v".equals(args[0])) {
FileRealmUser u=decodeUser(args[2], new Hashtable());
System.out.println("user: "+u.getName());
System.out.println("verifies: "+
SSHA.verify(u.getSalt(), u.getHash(),
args[1].getBytes()));
}
} catch (Exception e) {
e.printStackTrace(System.out);
}
|
private void | reduceGroups(java.lang.String[] groupList)This method reduces the group size by 1 and remove group name from
internal group list if resulting group size is 0.
if (groupList != null) {
for (int i=0; i < groupList.length; i++) {
Integer groupSize = (Integer)groupSizeMap.get(groupList[i]);
if (groupSize != null) {
int gpSize = groupSize.intValue() - 1;
if (gpSize > 0) {
groupSizeMap.put(groupList[i], new Integer(gpSize));
} else {
groupSizeMap.remove(groupList[i]);
}
}
}
}
|
public void | refresh()Refreshes the realm data so that new users/groups are visible.
A new FileRealm instance is created and initialized from the
keyfile on disk. The new instance is installed in the Realm registry
so future Realm.getInstance() calls will obtain the new data. Any
existing references to this instance (e.g. in active LoginModule
sessions) are unaffected.
if (_logger.isLoggable(Level.FINE)) {
_logger.fine("Reloading file realm data.");
}
FileRealm newRealm = new FileRealm();
try {
newRealm.init(getProperties());
Realm.updateInstance(newRealm, this.getName());
} catch (Exception e) {
throw new BadRealmException(e.toString());
}
|
public synchronized void | removeUser(java.lang.String name)Remove user from file realm. User must exist.
if (!userTable.containsKey(name)) {
String msg = sm.getString("filerealm.nouser", name);
throw new NoSuchUserException(msg);
}
FileRealmUser oldUser = (FileRealmUser)userTable.get(name);
userTable.remove(name);
reduceGroups(oldUser.getGroups());
|
private static void | setPassword(FileRealmUser user, java.lang.String pwd)Sets the password in a user object. Of course the password is not
really stored so a salt is generated, hash computed, and these two
values are stored in the user object provided.
assert (user != null);
byte[] pwdBytes = pwd.getBytes();
SecureRandom rng=new SecureRandom();
byte[] salt=new byte[SALT_SIZE];
rng.nextBytes(salt);
user.setSalt(salt);
byte[] hash = SSHA.compute(salt, pwdBytes);
user.setHash(hash);
|
public synchronized void | updateUser(java.lang.String name, java.lang.String password, java.lang.String[] groups)Update data for an existing user. User must exist. This is equivalent
to calling removeUser() followed by addUser().
updateUser(name, name, password, groups);
|
public synchronized void | updateUser(java.lang.String name, java.lang.String newName, java.lang.String password, java.lang.String[] groups)Update data for an existing user. User must exist.
// user to modify must exist first
validateUserName(name);
if (!userTable.containsKey(name)) {
String msg = sm.getString("filerealm.nouser", name);
throw new NoSuchUserException(msg);
}
// do general validation
validateUserName(newName);
validateGroupList(groups);
if (password != null) { // null here means re-use previous so is ok
validatePassword(password);
}
// can't duplicate unless modifying itself
if (!name.equals(newName) && userTable.containsKey(newName)) {
String msg = sm.getString("filerealm.dupuser", name);
throw new BadRealmException(msg);
}
FileRealmUser oldUser = (FileRealmUser)userTable.get(name);
assert (oldUser != null);
// create user using new name
FileRealmUser newUser = new FileRealmUser(newName);
// set groups as provided by parameter
changeGroups(oldUser.getGroups(), groups);
newUser.setGroups(groups);
// use old password if no new pwd given
if (password==null) {
newUser.setSalt(oldUser.getSalt());
newUser.setHash(oldUser.getHash());
} else {
setPassword(newUser, password);
}
userTable.remove(name);
userTable.put(newName, newUser);
|
public static void | validateGroupList(java.lang.String[] groupList)Validates syntax of a list of group names.
This is equivalent to calling validateGroupName on every element
of the groupList.
if (groupList == null || groupList.length == 0) {
return; // empty list is ok
}
for (int i=0; i<groupList.length; i++) {
validateGroupName(groupList[i]);
}
|
public static void | validateGroupName(java.lang.String group)Validates syntax of a group name.
This method throws an exception if the provided value is not
valid. The message of the exception provides a reason why it is
not valid. This is used internally by add/modify User to
validate the client-provided values. It is not necessary for
the client to call these methods first. However, these are
provided as public methods for convenience in case some client
(e.g. GUI client) wants to provide independent field validation
prior to calling add/modify user.
if (group == null || group.length() == 0) {
String msg = sm.getString("filerealm.nogroup");
throw new IASSecurityException(msg);
}
if (!isValid(group, false)) {
String msg = sm.getString("filerealm.badchars", group);
throw new IASSecurityException(msg);
}
if (!group.equals(group.trim())) {
String msg = sm.getString("filerealm.badspaces", group);
throw new IASSecurityException(msg);
}
|
public static void | validatePassword(java.lang.String pwd)Validates syntax of a password.
This method throws an exception if the provided value is not
valid. The message of the exception provides a reason why it is
not valid. This is used internally by add/modify User to
validate the client-provided values. It is not necessary for
the client to call these methods first. However, these are
provided as public methods for convenience in case some client
(e.g. GUI client) wants to provide independent field validation
prior to calling add/modify user.
if (pwd == null) {
String msg = sm.getString("filerealm.emptypwd");
throw new IASSecurityException(msg);
}
if (!pwd.equals(pwd.trim())) {
String msg = sm.getString("filerealm.badspacespwd");
throw new IASSecurityException(msg);
}
|
public static void | validateUserName(java.lang.String name)Validates syntax of a user name.
This method throws an exception if the provided value is not
valid. The message of the exception provides a reason why it is
not valid. This is used internally by add/modify User to
validate the client-provided values. It is not necessary for
the client to call these methods first. However, these are
provided as public methods for convenience in case some client
(e.g. GUI client) wants to provide independent field validation
prior to calling add/modify user.
if (name == null || name.length() == 0) {
String msg = sm.getString("filerealm.noname");
throw new IASSecurityException(msg);
}
if (!isValid(name, true)) {
String msg = sm.getString("filerealm.badname", name);
throw new IASSecurityException(msg);
}
if (!name.equals(name.trim())) {
String msg = sm.getString("filerealm.badspaces", name);
throw new IASSecurityException(msg);
}
|
public void | writeKeyFile(java.lang.String filename)Write keyfile data out to disk. The file generation is sychronized
within this class only, caller is responsible for any other
file locking or revision management as deemed necessary.
synchronized(FileRealm.class) {
FileOutputStream out = null;
try {
out = new FileOutputStream(filename);
Iterator names = userTable.keySet().iterator();
while (names.hasNext()) {
String name = (String)names.next();
FileRealmUser ud = (FileRealmUser)userTable.get(name);
String entry = encodeUser(name, ud);
out.write(entry.getBytes());
}
} catch (IOException e) {
throw e;
} catch (Exception e) {
String msg = sm.getString("filerealm.badwrite", e.toString());
throw new IOException(msg);
} finally {
if (out != null) {
out.close();
}
}
}
_logger.fine("Done writing "+filename);
|