001: /*
002: * Copyright 2006 Rui Damas <rui.damas at gmail com>
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 contrib.winstone;
008:
009: import java.sql.*;
010: import java.util.*;
011:
012: import winstone.*;
013:
014: /**
015: * A JDBC authentication realm to be used with Winstone Servelet container.
016: * <p>
017: * --JDBCRealm.url and --JDBCRealm.user are required.
018: * </p>
019: *
020: * @author Rui Damas
021: */
022: public class JDBCRealm implements AuthenticationRealm {
023:
024: // Command line arguments prefix
025: public static String ARGS = "JDBCRealm.";
026:
027: // Command line arguments for connecting
028: public static String ARGS_DRIVER = ARGS + "driver", ARGS_URL = ARGS
029: + "url", ARGS_USER = ARGS + "user", ARGS_PASSWORD = ARGS
030: + "password";
031:
032: // Command line arguments to SQL identifiers
033: public static String ARGS_USER_REL = ARGS + "userRel",
034: ARGS_USER_NAME_COL = ARGS + "userNameCol",
035: ARGS_USER_CRED_COL = ARGS + "userCredCol",
036: ARGS_USER_ROLE_REL = ARGS + "userRoleRel",
037: ARGS_ROLE_NAME_COL = ARGS + "roleNameCol";
038:
039: // Defaults for SQL identifiers
040: public static String DEFAULT_USER_REL = "web_users",
041: DEFAULT_USER_NAME_COL = "username",
042: DEFAULT_USER_CRED_COL = "credential",
043: DEFAULT_USER_ROLE_REL = "web_user_roles",
044: DEFAULT_ROLE_NAME_COL = "rolename";
045:
046: private Connection connection;
047:
048: private final String url, user, password, retriveUserQuery,
049: authenticationQueryPostfix, userRolesQuery;
050:
051: /**
052: Creates a new instance of JDBCAuthenticationRealm.
053: <p>
054: If a <code>"JDBCRealm.driver"</code> exists in the <code>args</code>
055: map an atempt to load the class will be made and
056: a success message will be printed to <code>System.out</code>,
057: or, if the class fails to load,
058: an error message will be printed to <code>System.err</code>.
059: </p>
060: */
061: public JDBCRealm(Set rolesAllowed, Map<String, String> args) {
062: // Get connection arguments
063: String driver = args.get(ARGS_DRIVER), url = args.get(ARGS_URL), user = args
064: .get(ARGS_USER), password = args.get(ARGS_PASSWORD);
065:
066: this .url = url;
067: this .user = user;
068: this .password = password;
069:
070: // Get SQL identifier arguments
071: String userRel = args.get(ARGS_USER_REL), userNameCol = args
072: .get(ARGS_USER_NAME_COL), userCredCol = args
073: .get(ARGS_USER_CRED_COL), userRoleRel = args
074: .get(ARGS_USER_ROLE_REL), roleNameCol = args
075: .get(ARGS_ROLE_NAME_COL);
076:
077: // Get defaults if necessary
078: if (userRel == null)
079: userRel = DEFAULT_USER_REL;
080: if (userNameCol == null)
081: userNameCol = DEFAULT_USER_NAME_COL;
082: if (userCredCol == null)
083: userCredCol = DEFAULT_USER_CRED_COL;
084: if (userRoleRel == null)
085: userRoleRel = DEFAULT_USER_ROLE_REL;
086: if (roleNameCol == null)
087: roleNameCol = DEFAULT_ROLE_NAME_COL;
088:
089: retriveUserQuery = "SELECT 1\n" + " FROM \"" + userRel
090: + "\"\n" + " WHERE \"" + userNameCol + "\" = ?";
091:
092: // Prepare query prefixes
093: authenticationQueryPostfix = "\n AND \"" + userCredCol
094: + "\" = ?";
095:
096: userRolesQuery = "SELECT \"" + roleNameCol + "\"\n"
097: + " FROM \"" + userRoleRel + "\"\n" + " WHERE \""
098: + userNameCol + "\" = ?";
099:
100: // If the driver was specified
101: if (driver != null)
102: try {
103: // Try to load the driver
104: Class.forName(driver);
105: // and notify if loaded
106: System.out.println("JDBCRealm loaded jdbc driver: "
107: + driver);
108: } catch (ClassNotFoundException cnfe) {
109: // Notify if fails
110: System.err
111: .println("JDBCRealm failed to load jdbc driver: "
112: + driver);
113: }
114: }
115:
116: public AuthenticationPrincipal getPrincipal(String userName,
117: String password, boolean usePassword) {
118: try {
119: // Get a connection
120: if ((connection == null) || connection.isClosed())
121: connection = DriverManager.getConnection(url, user,
122: password);
123: // Query for user
124: String query = retriveUserQuery;
125: if (usePassword)
126: query = query + authenticationQueryPostfix;
127: PreparedStatement ps = connection.prepareStatement(query);
128: ps.setString(1, userName);
129: if (usePassword)
130: ps.setString(2, password);
131: ResultSet resultSet = ps.executeQuery();
132: // If there is a user (row)
133: if (resultSet.next()) {
134: // Query for the user roles
135: query = userRolesQuery;
136: ps = connection.prepareStatement(query);
137: ps.setString(1, userName);
138: resultSet = ps.executeQuery();
139: // Load list
140: List<String> roles = new Vector<String>();
141: while (resultSet.next())
142: roles.add(resultSet.getString(1));
143: return new AuthenticationPrincipal(userName, password,
144: roles);
145: }
146: } catch (SQLException sqle) {
147: sqle.printStackTrace();
148: }
149: return null;
150: }
151:
152: /**
153: * Authenticate the user - do we know them ? Return a distinct id once we
154: * know them.
155: * @return <code>getPrincipal(userName, password, true);</code>
156: */
157: public AuthenticationPrincipal authenticateByUsernamePassword(
158: String userName, String password) {
159: return getPrincipal(userName, password, true);
160: }
161:
162: /**
163: * Retrieve an authenticated user
164: * @return <code>getPrincipal(userName, password, false);</code>
165: */
166: public AuthenticationPrincipal retrieveUser(String userName) {
167: return getPrincipal(userName, null, false);
168: }
169: }
|