001: /*
002: * Copyright 2004 Outerthought bvba and Schaubroeck nv
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: package org.outerj.daisy.authentication.impl;
017:
018: import org.outerj.daisy.authentication.spi.AuthenticationException;
019: import org.outerj.daisy.authentication.spi.*;
020: import org.outerj.daisy.repository.Credentials;
021: import org.outerj.daisy.repository.user.User;
022: import org.outerj.daisy.repository.user.UserManager;
023: import org.outerj.daisy.jdbcutil.JdbcHelper;
024: import org.outerj.daisy.plugin.PluginRegistry;
025: import org.apache.avalon.framework.configuration.Configuration;
026: import org.apache.avalon.framework.configuration.ConfigurationException;
027: import org.apache.commons.logging.Log;
028: import org.apache.commons.logging.LogFactory;
029:
030: import javax.sql.DataSource;
031: import javax.annotation.PreDestroy;
032: import java.sql.Connection;
033: import java.sql.PreparedStatement;
034: import java.sql.ResultSet;
035: import java.security.MessageDigest;
036:
037: /**
038: * Responsible for creating and registering the DaisyAuthenticationScheme with the UserAuthenticator.
039: *
040: */
041: public class DaisyAuthenticationFactory {
042: private final Log log = LogFactory.getLog(getClass());
043: private PluginRegistry pluginRegistry;
044: private DataSource dataSource;
045: private JdbcHelper jdbcHelper;
046: private boolean enableCaching;
047: private long maxCacheDuration;
048: private int maxCacheSize;
049: private AuthenticationScheme authScheme;
050: private final static String AUTH_SCHEME_NAME = "daisy";
051:
052: public DaisyAuthenticationFactory(Configuration configuration,
053: DataSource dataSource, PluginRegistry pluginRegistry)
054: throws Exception {
055: this .dataSource = dataSource;
056: this .pluginRegistry = pluginRegistry;
057: this .configure(configuration);
058: this .initialize();
059: }
060:
061: private void configure(Configuration configuration)
062: throws ConfigurationException {
063: Configuration cacheConf = configuration.getChild("cache");
064: if (cacheConf.getAttributeAsBoolean("enabled")) {
065: enableCaching = true;
066: maxCacheSize = cacheConf.getAttributeAsInteger(
067: "maxCacheSize", 3000);
068: maxCacheDuration = cacheConf.getAttributeAsLong(
069: "maxCacheDuration", 30 * 60 * 1000); // default: half an hour
070: }
071: }
072:
073: private void initialize() throws Exception {
074: jdbcHelper = JdbcHelper.getInstance(dataSource, log);
075: if (enableCaching) {
076: authScheme = new CachingAuthenticationScheme(
077: new DaisyAuthenticationScheme(), maxCacheDuration,
078: maxCacheSize);
079: } else {
080: authScheme = new DaisyAuthenticationScheme();
081: }
082: pluginRegistry.addPlugin(AuthenticationScheme.class,
083: AUTH_SCHEME_NAME, authScheme);
084: }
085:
086: @PreDestroy
087: public void destroy() {
088: pluginRegistry.removePlugin(AuthenticationScheme.class,
089: AUTH_SCHEME_NAME, authScheme);
090: }
091:
092: class DaisyAuthenticationScheme implements AuthenticationScheme {
093:
094: public String getDescription() {
095: return "Daisy built-in";
096: }
097:
098: public void clearCaches() {
099: // do nothing
100: }
101:
102: public boolean check(Credentials credentials)
103: throws AuthenticationException {
104: Connection conn = null;
105: PreparedStatement stmt = null;
106: ResultSet rs;
107: try {
108: conn = dataSource.getConnection();
109: stmt = conn
110: .prepareStatement("select login, password, default_role, id from users where login = ?");
111: stmt.setString(1, credentials.getLogin());
112: rs = stmt.executeQuery();
113:
114: if (!rs.next())
115: return false;
116:
117: // To be sure the login string is exactly the same (e.g. SQL search might be case-insensitive).
118: if (!credentials.getLogin().equals(
119: rs.getString("login")))
120: return false;
121:
122: String password = rs.getString("password");
123:
124: if (password == null
125: || !password.equals(hashPassword(credentials
126: .getPassword())))
127: return false;
128:
129: return true;
130: } catch (Exception e) {
131: throw new AuthenticationException(
132: "Error trying to authenticate user with Daisy Authentication Scheme.",
133: e);
134: } finally {
135: jdbcHelper.closeStatement(stmt);
136: jdbcHelper.closeConnection(conn);
137: }
138: }
139:
140: public User createUser(Credentials crendentials,
141: UserManager userManager) throws AuthenticationException {
142: return null;
143: }
144: }
145:
146: private static String hashPassword(String password) {
147: if (password == null)
148: return null;
149: try {
150: byte[] data = password.getBytes("UTF-8");
151: MessageDigest digest = MessageDigest.getInstance("SHA-1");
152: digest.update(data);
153: byte[] result = digest.digest();
154: return toHexString(result);
155: } catch (Exception e) {
156: throw new RuntimeException(
157: "Problem calculating password hash.", e);
158: }
159: }
160:
161: private static String toHexString(byte[] b) {
162: StringBuilder sb = new StringBuilder(b.length * 2);
163: for (int i = 0; i < b.length; i++) {
164: sb.append(hexChar[(b[i] & 0xf0) >>> 4]);
165: sb.append(hexChar[b[i] & 0x0f]);
166: }
167: return sb.toString();
168: }
169:
170: static char[] hexChar = { '0', '1', '2', '3', '4', '5', '6', '7',
171: '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
172: }
|