001: /*
002: * Copyright 2003-2006 Rick Knowles <winstone-devel at lists sourceforge net>
003: * Distributed under the terms of either:
004: * - the common development and distribution license (CDDL), v1.0; or
005: * - the GNU Lesser General Public License, v2.1 or later
006: */
007: package winstone.realm;
008:
009: import java.io.File;
010: import java.io.FileInputStream;
011: import java.io.InputStream;
012: import java.util.ArrayList;
013: import java.util.Arrays;
014: import java.util.Hashtable;
015: import java.util.List;
016: import java.util.Map;
017: import java.util.Set;
018: import java.util.StringTokenizer;
019:
020: import javax.xml.parsers.DocumentBuilder;
021: import javax.xml.parsers.DocumentBuilderFactory;
022:
023: import org.w3c.dom.Document;
024: import org.w3c.dom.Node;
025:
026: import winstone.AuthenticationPrincipal;
027: import winstone.AuthenticationRealm;
028: import winstone.Logger;
029: import winstone.WinstoneException;
030: import winstone.WinstoneResourceBundle;
031:
032: /**
033: * @author rickk
034: * @version $Id: FileRealm.java,v 1.4 2006/08/30 04:07:52 rickknowles Exp $
035: */
036: public class FileRealm implements AuthenticationRealm {
037: private static final WinstoneResourceBundle REALM_RESOURCES = new WinstoneResourceBundle(
038: "winstone.realm.LocalStrings");
039:
040: final String FILE_NAME_ARGUMENT = "fileRealm.configFile";
041: final String DEFAULT_FILE_NAME = "users.xml";
042: final String ELEM_USER = "user";
043: final String ATT_USERNAME = "username";
044: final String ATT_PASSWORD = "password";
045: final String ATT_ROLELIST = "roles";
046: private Map passwords;
047: private Map roles;
048:
049: /**
050: * Constructor - this sets up an authentication realm, using the file
051: * supplied on the command line as a source of userNames/passwords/roles.
052: */
053: public FileRealm(Set rolesAllowed, Map args) {
054: this .passwords = new Hashtable();
055: this .roles = new Hashtable();
056:
057: // Get the filename and parse the xml doc
058: String realmFileName = args.get(FILE_NAME_ARGUMENT) == null ? DEFAULT_FILE_NAME
059: : (String) args.get(FILE_NAME_ARGUMENT);
060: File realmFile = new File(realmFileName);
061: if (!realmFile.exists())
062: throw new WinstoneException(REALM_RESOURCES.getString(
063: "FileRealm.FileNotFound", realmFile.getPath()));
064: try {
065: InputStream inFile = new FileInputStream(realmFile);
066: Document doc = this .parseStreamToXML(inFile);
067: inFile.close();
068: Node rootElm = doc.getDocumentElement();
069: for (int n = 0; n < rootElm.getChildNodes().getLength(); n++) {
070: Node child = rootElm.getChildNodes().item(n);
071:
072: if ((child.getNodeType() == Node.ELEMENT_NODE)
073: && (child.getNodeName().equals(ELEM_USER))) {
074: String userName = null;
075: String password = null;
076: String roleList = null;
077: // Loop through for attributes
078: for (int j = 0; j < child.getAttributes()
079: .getLength(); j++) {
080: Node this Att = child.getAttributes().item(j);
081: if (this Att.getNodeName().equals(ATT_USERNAME))
082: userName = this Att.getNodeValue();
083: else if (this Att.getNodeName().equals(
084: ATT_PASSWORD))
085: password = this Att.getNodeValue();
086: else if (this Att.getNodeName().equals(
087: ATT_ROLELIST))
088: roleList = this Att.getNodeValue();
089: }
090:
091: if ((userName == null) || (password == null)
092: || (roleList == null))
093: Logger.log(Logger.FULL_DEBUG, REALM_RESOURCES,
094: "FileRealm.SkippingUser", userName);
095: else {
096: // Parse the role list into an array and sort it
097: StringTokenizer st = new StringTokenizer(
098: roleList, ",");
099: List rl = new ArrayList();
100: for (; st.hasMoreTokens();) {
101: String currentRole = st.nextToken();
102: if (rolesAllowed.contains(currentRole))
103: rl.add(currentRole);
104: }
105: Object roleArray[] = rl.toArray();
106: Arrays.sort(roleArray);
107: this .passwords.put(userName, password);
108: this .roles.put(userName, Arrays
109: .asList(roleArray));
110: }
111: }
112: }
113: Logger
114: .log(Logger.DEBUG, REALM_RESOURCES,
115: "FileRealm.Initialised", ""
116: + this .passwords.size());
117: } catch (java.io.IOException err) {
118: throw new WinstoneException(REALM_RESOURCES
119: .getString("FileRealm.ErrorLoading"), err);
120: }
121: }
122:
123: /**
124: * Get a parsed XML DOM from the given inputstream. Used to process the
125: * web.xml application deployment descriptors.
126: */
127: private Document parseStreamToXML(InputStream in) {
128: try {
129: // Use JAXP to create a document builder
130: DocumentBuilderFactory factory = DocumentBuilderFactory
131: .newInstance();
132: factory.setExpandEntityReferences(false);
133: factory.setValidating(false);
134: factory.setNamespaceAware(false);
135: factory.setIgnoringComments(true);
136: factory.setCoalescing(true);
137: factory.setIgnoringElementContentWhitespace(true);
138: DocumentBuilder builder = factory.newDocumentBuilder();
139: return builder.parse(in);
140: } catch (Throwable errParser) {
141: throw new WinstoneException(REALM_RESOURCES
142: .getString("FileRealm.XMLParseError"), errParser);
143: }
144: }
145:
146: /**
147: * Authenticate the user - do we know them ? Return a principal once we know
148: * them
149: */
150: public AuthenticationPrincipal authenticateByUsernamePassword(
151: String userName, String password) {
152: if ((userName == null) || (password == null))
153: return null;
154:
155: String realPassword = (String) this .passwords.get(userName);
156: if (realPassword == null)
157: return null;
158: else if (!realPassword.equals(password))
159: return null;
160: else
161: return new AuthenticationPrincipal(userName, password,
162: (List) this .roles.get(userName));
163: }
164:
165: /**
166: * Retrieve an authenticated user
167: */
168: public AuthenticationPrincipal retrieveUser(String userName) {
169: return new AuthenticationPrincipal(userName,
170: (String) this .passwords.get(userName),
171: (List) this.roles.get(userName));
172: }
173: }
|