Author: iocanel
Date: Wed Sep 15 09:13:56 2010
New Revision: 997236
URL: http://svn.apache.org/viewvc?rev=997236&view=rev
Log:
Added a JDBC login module.
Added:
karaf/trunk/jaas/modules/src/main/java/org/apache/karaf/jaas/modules/jdbc/
karaf/trunk/jaas/modules/src/main/java/org/apache/karaf/jaas/modules/jdbc/JDBCLoginModule.java
Added:
karaf/trunk/jaas/modules/src/main/java/org/apache/karaf/jaas/modules/jdbc/JDBCLoginModule.java
URL:
http://svn.apache.org/viewvc/karaf/trunk/jaas/modules/src/main/java/org/apache/karaf/jaas/modules/jdbc/JDBCLoginModule.java?rev=997236&view=auto
==============================================================================
---
karaf/trunk/jaas/modules/src/main/java/org/apache/karaf/jaas/modules/jdbc/JDBCLoginModule.java
(added)
+++
karaf/trunk/jaas/modules/src/main/java/org/apache/karaf/jaas/modules/jdbc/JDBCLoginModule.java
Wed Sep 15 09:13:56 2010
@@ -0,0 +1,219 @@
+/*
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * under the License.
+ */
+package org.apache.karaf.jaas.modules.jdbc;
+
+import java.io.IOException;
+import java.security.Principal;
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.HashSet;
+import java.util.Map;
+import javax.naming.InitialContext;
+import javax.security.auth.Subject;
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.NameCallback;
+import javax.security.auth.callback.PasswordCallback;
+import javax.security.auth.callback.UnsupportedCallbackException;
+import javax.security.auth.login.LoginException;
+import javax.sql.DataSource;
+import javax.sql.XADataSource;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.karaf.jaas.modules.AbstractKarafLoginModule;
+import org.apache.karaf.jaas.modules.RolePrincipal;
+import org.apache.karaf.jaas.modules.UserPrincipal;
+import org.apache.karaf.jaas.modules.properties.PropertiesLoginModule;
+import org.osgi.framework.ServiceReference;
+
+/**
+ *
+ * @author iocanel
+ */
+public class JDBCLoginModule extends AbstractKarafLoginModule {
+
+ private static final Log LOG =
LogFactory.getLog(PropertiesLoginModule.class);
+ private static final String DATASOURCE = "datasource";
+ private static final String JNDI = "jndi:";
+ private static final String OSGI = "osgi:";
+ private String datasourceURL;
+ protected String passwordQuery = "SELECT PASSWORD FROM USERS WHERE
USERNAME=?";
+ protected String roleQuery = "SELECT ROLE FROM ROLES WHERE USERNAME=?";
+
+ public void initialize(Subject subject, CallbackHandler callbackHandler,
Map<String, ?> sharedState, Map<String, ?> options) {
+ super.initialize(subject, callbackHandler, options);
+ datasourceURL = (String) options.get(DATASOURCE);
+ if (datasourceURL == null || datasourceURL.isEmpty()) {
+ LOG.error("No datasource was specified ");
+ } else if (!datasourceURL.startsWith(JNDI) &&
!datasourceURL.startsWith(OSGI)) {
+ LOG.error("Invalid datasource lookup protocol");
+ }
+ }
+
+ /**
+ * Looks up a datasource from the url. The datasource can be passed either
as jndi name or osgi ldap filter.
+ * @param url
+ * @return
+ * @throws Exception
+ */
+ public Object createDatasource(String url) throws Exception {
+ if (url == null) {
+ throw new Exception("Illegal datasource url format. Datasource URL
cannot be null.");
+ } else if (url.trim().isEmpty()) {
+ throw new Exception("Illegal datasource url format. Datasource URL
cannot be empty.");
+ } else if (url.startsWith(JNDI)) {
+ String jndiName = url.substring(JNDI.length());
+ InitialContext ic = new InitialContext();
+ DataSource ds = (DataSource) ic.lookup(jndiName);
+ return ds;
+ } else if (url.startsWith(OSGI)) {
+ String osgiFilter = url.substring(OSGI.length());
+ String clazz = null;
+ String filter = null;
+ String[] tokens = osgiFilter.split("/", 2);
+ if (tokens != null) {
+ if (tokens.length > 0) {
+ clazz = tokens[0];
+ }
+ if (tokens.length > 1) {
+ filter = tokens[1];
+ }
+ }
+ ServiceReference[] references =
bundleContext.getServiceReferences(clazz, filter);
+ if (references != null) {
+ ServiceReference ref = references[0];
+ return bundleContext.getService(ref);
+ } else {
+ throw new Exception("Unable to find service reference for
datasource: " + clazz + "/" + filter);
+ }
+ } else {
+ throw new Exception("Illegal datasource url format");
+ }
+ }
+
+ public boolean login() throws LoginException {
+ Connection connection = null;
+
+ PreparedStatement passwordStatement = null;
+ PreparedStatement roleStatement = null;
+
+ ResultSet passwordResultSet = null;
+ ResultSet roleResultSet = null;
+
+ Callback[] callbacks = new Callback[2];
+ callbacks[0] = new NameCallback("Username: ");
+ callbacks[1] = new PasswordCallback("Password: ", false);
+
+ try {
+ callbackHandler.handle(callbacks);
+ } catch (IOException ioe) {
+ throw new LoginException(ioe.getMessage());
+ } catch (UnsupportedCallbackException uce) {
+ throw new LoginException(uce.getMessage() + " not available to
obtain information from user");
+ }
+
+ user = ((NameCallback) callbacks[0]).getName();
+
+ char[] tmpPassword = ((PasswordCallback) callbacks[1]).getPassword();
+ if (tmpPassword == null) {
+ tmpPassword = new char[0];
+ }
+
+ String password = new String(tmpPassword);
+ principals = new HashSet<Principal>();
+
+ try {
+ Object credentialsDatasource = createDatasource(datasourceURL);
+
+ if (credentialsDatasource == null) {
+ throw new LoginException("Cannot obtain data source:" +
datasourceURL);
+ } else if (credentialsDatasource instanceof DataSource) {
+ connection = ((DataSource)
credentialsDatasource).getConnection();
+ } else if (credentialsDatasource instanceof XADataSource) {
+ connection = ((XADataSource)
credentialsDatasource).getXAConnection().getConnection();
+ } else {
+ throw new LoginException("Unknow dataSource type " +
credentialsDatasource.getClass());
+ }
+
+ //Retrieve user credentials from database.
+ passwordStatement = connection.prepareStatement(passwordQuery);
+ passwordStatement.setString(1, user);
+ passwordResultSet = passwordStatement.executeQuery();
+
+ if (!passwordResultSet.next()) {
+ throw new LoginException("User " + user + " does not exist");
+ } else {
+ String storedPassword = passwordResultSet.getString(1);
+
+ encryption = getEncryption();
+ if (encryption != null && encryption.checkPassword(password,
storedPassword)) {
+ principals.add(new UserPrincipal(user));
+ } else if (encryption == null &&
password.equals(storedPassword)) {
+ principals.add(new UserPrincipal(user));
+ } else {
+ throw new LoginException("Password for " + user + " does
not match");
+ }
+ }
+
+ //Retrieve user roles from database
+ roleStatement = connection.prepareStatement(roleQuery);
+ roleStatement.setString(1, user);
+ roleResultSet = roleStatement.executeQuery();
+ while (roleResultSet.next()) {
+ String role = roleResultSet.getString(1);
+ principals.add(new RolePrincipal(role));
+ }
+ } catch (Exception ex) {
+ throw new LoginException("Error has occured while retrieving
credentials from databse:" + ex.getMessage());
+ } finally {
+ try {
+ if (passwordResultSet != null &&
!passwordResultSet.isClosed()) {
+ passwordResultSet.close();
+ }
+ if (passwordStatement != null &&
!passwordStatement.isClosed()) {
+ passwordStatement.close();
+ }
+ if (roleResultSet != null && !roleResultSet.isClosed()) {
+ roleResultSet.close();
+ }
+ if (roleStatement != null && !roleStatement.isClosed()) {
+ roleStatement.close();
+ }
+ if (connection != null && !connection.isClosed()) {
+ connection.close();
+ }
+ } catch (SQLException ex) {
+ LOG.warn("Failed to clearly close connection to the
database:", ex);
+ }
+ }
+ return true;
+ }
+
+ public boolean abort() throws LoginException {
+ return true;
+ }
+
+ public boolean logout() throws LoginException {
+ subject.getPrincipals().removeAll(principals);
+ principals.clear();
+ if (debug) {
+ LOG.debug("logout");
+ }
+ return true;
+ }
+}