You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@karaf.apache.org by gn...@apache.org on 2014/05/30 16:05:38 UTC
[1/2] git commit: [KARAF-2923] Add support for regions in JMX events
Repository: karaf
Updated Branches:
refs/heads/master f7bb021c4 -> 232bf6c04
[KARAF-2923] Add support for regions in JMX events
Project: http://git-wip-us.apache.org/repos/asf/karaf/repo
Commit: http://git-wip-us.apache.org/repos/asf/karaf/commit/2a1ad299
Tree: http://git-wip-us.apache.org/repos/asf/karaf/tree/2a1ad299
Diff: http://git-wip-us.apache.org/repos/asf/karaf/diff/2a1ad299
Branch: refs/heads/master
Commit: 2a1ad299adca2653be96d79870b5ccf1af4f0045
Parents: f7bb021
Author: Guillaume Nodet <gn...@gmail.com>
Authored: Fri May 30 09:48:31 2014 +0200
Committer: Guillaume Nodet <gn...@gmail.com>
Committed: Fri May 30 09:48:31 2014 +0200
----------------------------------------------------------------------
.../org/apache/karaf/features/FeatureEvent.java | 8 +++++++-
.../features/internal/service/Deployer.java | 19 ++++++++++++++-----
.../internal/service/FeaturesServiceImpl.java | 13 ++++++++-----
.../management/FeaturesServiceMBean.java | 4 +++-
.../management/codec/JmxFeatureEvent.java | 3 +++
.../features/internal/service/DeployerTest.java | 5 +++--
6 files changed, 38 insertions(+), 14 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/karaf/blob/2a1ad299/features/core/src/main/java/org/apache/karaf/features/FeatureEvent.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/FeatureEvent.java b/features/core/src/main/java/org/apache/karaf/features/FeatureEvent.java
index 516c988..5a26e46 100644
--- a/features/core/src/main/java/org/apache/karaf/features/FeatureEvent.java
+++ b/features/core/src/main/java/org/apache/karaf/features/FeatureEvent.java
@@ -27,12 +27,14 @@ public class FeatureEvent extends EventObject {
private final EventType type;
private final Feature feature;
+ private final String region;
private final boolean replay;
- public FeatureEvent(Feature feature, EventType type, boolean replay) {
+ public FeatureEvent(EventType type, Feature feature, String region, boolean replay) {
super(feature);
this.type = type;
this.feature = feature;
+ this.region = region;
this.replay = replay;
}
@@ -44,6 +46,10 @@ public class FeatureEvent extends EventObject {
return feature;
}
+ public String getRegion() {
+ return region;
+ }
+
public boolean isReplay() {
return replay;
}
http://git-wip-us.apache.org/repos/asf/karaf/blob/2a1ad299/features/core/src/main/java/org/apache/karaf/features/internal/service/Deployer.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/service/Deployer.java b/features/core/src/main/java/org/apache/karaf/features/internal/service/Deployer.java
index 4d289cb..81cc0f8 100644
--- a/features/core/src/main/java/org/apache/karaf/features/internal/service/Deployer.java
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/service/Deployer.java
@@ -767,12 +767,21 @@ public class Deployer {
}
// Call listeners
- // TODO: add region information and avoid flattening
- for (Feature feature : apply(flatten(delFeatures), map(dstate.features))) {
- callback.callListeners(new FeatureEvent(feature, FeatureEvent.EventType.FeatureUninstalled, false));
+ for (Map.Entry<String, Set<String>> entry : delFeatures.entrySet()) {
+ for (String name : entry.getValue()) {
+ Feature feature = dstate.features.get(name);
+ if (feature != null) {
+ callback.callListeners(new FeatureEvent(FeatureEvent.EventType.FeatureUninstalled, feature, entry.getKey(), false));
+ }
+ }
}
- for (Feature feature : apply(flatten(newFeatures), map(dstate.features))) {
- callback.callListeners(new FeatureEvent(feature, FeatureEvent.EventType.FeatureInstalled, false));
+ for (Map.Entry<String, Set<String>> entry : newFeatures.entrySet()) {
+ for (String name : entry.getValue()) {
+ Feature feature = dstate.features.get(name);
+ if (feature != null) {
+ callback.callListeners(new FeatureEvent(FeatureEvent.EventType.FeatureInstalled, feature, entry.getKey(), false));
+ }
+ }
}
print("Done.", verbose);
http://git-wip-us.apache.org/repos/asf/karaf/blob/2a1ad299/features/core/src/main/java/org/apache/karaf/features/internal/service/FeaturesServiceImpl.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/service/FeaturesServiceImpl.java b/features/core/src/main/java/org/apache/karaf/features/internal/service/FeaturesServiceImpl.java
index ce01342..faabc88 100644
--- a/features/core/src/main/java/org/apache/karaf/features/internal/service/FeaturesServiceImpl.java
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/service/FeaturesServiceImpl.java
@@ -32,6 +32,7 @@ import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.TreeMap;
import java.util.TreeSet;
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
@@ -266,18 +267,20 @@ public class FeaturesServiceImpl implements FeaturesService, Deployer.DeployCall
listeners.add(listener);
try {
Set<String> repositories = new TreeSet<>();
- Set<String> installedFeatures = new TreeSet<>();
+ Map<String, Set<String>> installedFeatures = new TreeMap<>();
synchronized (lock) {
repositories.addAll(state.repositories);
- installedFeatures.addAll(state.installedFeatures.keySet());
+ installedFeatures.putAll(copy(state.installedFeatures));
}
for (String uri : repositories) {
Repository repository = new RepositoryImpl(URI.create(uri));
listener.repositoryEvent(new RepositoryEvent(repository, RepositoryEvent.EventType.RepositoryAdded, true));
}
- for (String id : installedFeatures) {
- Feature feature = org.apache.karaf.features.internal.model.Feature.valueOf(id);
- listener.featureEvent(new FeatureEvent(feature, FeatureEvent.EventType.FeatureInstalled, true));
+ for (Map.Entry<String, Set<String>> entry : installedFeatures.entrySet()) {
+ for (String id : entry.getValue()) {
+ Feature feature = org.apache.karaf.features.internal.model.Feature.valueOf(id);
+ listener.featureEvent(new FeatureEvent(FeatureEvent.EventType.FeatureInstalled, feature, entry.getKey(), true));
+ }
}
} catch (Exception e) {
LOGGER.error("Error notifying listener about the current state", e);
http://git-wip-us.apache.org/repos/asf/karaf/blob/2a1ad299/features/core/src/main/java/org/apache/karaf/features/management/FeaturesServiceMBean.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/management/FeaturesServiceMBean.java b/features/core/src/main/java/org/apache/karaf/features/management/FeaturesServiceMBean.java
index 60e0f9b..9cce26b 100644
--- a/features/core/src/main/java/org/apache/karaf/features/management/FeaturesServiceMBean.java
+++ b/features/core/src/main/java/org/apache/karaf/features/management/FeaturesServiceMBean.java
@@ -52,6 +52,8 @@ public interface FeaturesServiceMBean {
String FEATURE_EVENT_EVENT_TYPE_UNINSTALLED = "Uninstalled";
+ String FEATURE_EVENT_REGION = "Region";
+
/**
* The item names in the CompositeData representing a feature
*/
@@ -70,7 +72,7 @@ public interface FeaturesServiceMBean {
* The item names in the CompositeData representing the event raised for
* feature events within the OSGi container by this bean
*/
- String[] FEATURE_EVENT = {FEATURE_NAME, FEATURE_VERSION, FEATURE_EVENT_EVENT_TYPE};
+ String[] FEATURE_EVENT = {FEATURE_NAME, FEATURE_VERSION, FEATURE_EVENT_REGION, FEATURE_EVENT_EVENT_TYPE};
String REPOSITORY_NAME = "Name";
http://git-wip-us.apache.org/repos/asf/karaf/blob/2a1ad299/features/core/src/main/java/org/apache/karaf/features/management/codec/JmxFeatureEvent.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/management/codec/JmxFeatureEvent.java b/features/core/src/main/java/org/apache/karaf/features/management/codec/JmxFeatureEvent.java
index 2319a15..65f00c1 100644
--- a/features/core/src/main/java/org/apache/karaf/features/management/codec/JmxFeatureEvent.java
+++ b/features/core/src/main/java/org/apache/karaf/features/management/codec/JmxFeatureEvent.java
@@ -38,6 +38,7 @@ public class JmxFeatureEvent {
Object[] itemValues = new Object[itemNames.length];
itemValues[0] = event.getFeature().getName();
itemValues[1] = event.getFeature().getVersion();
+ itemValues[2] = event.getRegion();
switch (event.getType()) {
case FeatureInstalled:
itemValues[2] = FeaturesServiceMBean.FEATURE_EVENT_EVENT_TYPE_INSTALLED;
@@ -71,10 +72,12 @@ public class JmxFeatureEvent {
itemTypes[0] = SimpleType.STRING;
itemTypes[1] = SimpleType.STRING;
itemTypes[2] = SimpleType.STRING;
+ itemTypes[3] = SimpleType.STRING;
itemDescriptions[0] = "The id of the feature";
itemDescriptions[1] = "The version of the feature";
itemDescriptions[2] = "The type of the event";
+ itemDescriptions[3] = "The region of this feature";
return new CompositeType("FeatureEvent", description, itemNames,
itemDescriptions, itemTypes);
http://git-wip-us.apache.org/repos/asf/karaf/blob/2a1ad299/features/core/src/test/java/org/apache/karaf/features/internal/service/DeployerTest.java
----------------------------------------------------------------------
diff --git a/features/core/src/test/java/org/apache/karaf/features/internal/service/DeployerTest.java b/features/core/src/test/java/org/apache/karaf/features/internal/service/DeployerTest.java
index 9478b67..f5e05d1 100644
--- a/features/core/src/test/java/org/apache/karaf/features/internal/service/DeployerTest.java
+++ b/features/core/src/test/java/org/apache/karaf/features/internal/service/DeployerTest.java
@@ -30,6 +30,7 @@ import java.util.jar.Manifest;
import org.apache.felix.utils.version.VersionRange;
import org.apache.karaf.features.Feature;
import org.apache.karaf.features.FeatureEvent;
+import org.apache.karaf.features.FeaturesService;
import org.apache.karaf.features.internal.support.TestBundle;
import org.apache.karaf.features.internal.support.TestDownloadManager;
import org.easymock.EasyMock;
@@ -164,9 +165,9 @@ public class DeployerTest {
EasyMock.expectLastCall();
callback.refreshPackages(EasyMock.eq(Collections.<Bundle>singleton(bundleA)));
EasyMock.expectLastCall();
- callback.callListeners(FeatureEventMatcher.eq(new FeatureEvent(f100, FeatureEvent.EventType.FeatureUninstalled, false)));
+ callback.callListeners(FeatureEventMatcher.eq(new FeatureEvent(FeatureEvent.EventType.FeatureUninstalled, f100, FeaturesService.ROOT_REGION, false)));
EasyMock.expectLastCall();
- callback.callListeners(FeatureEventMatcher.eq(new FeatureEvent(f101, FeatureEvent.EventType.FeatureInstalled, false)));
+ callback.callListeners(FeatureEventMatcher.eq(new FeatureEvent(FeatureEvent.EventType.FeatureInstalled, f101, FeaturesService.ROOT_REGION, false)));
EasyMock.expectLastCall();
EasyMock.replay(callback);
[2/2] git commit: [KARAF-2613] Add support for groups in JDBC login
module and backing engine
Posted by gn...@apache.org.
[KARAF-2613] Add support for groups in JDBC login module and backing engine
Project: http://git-wip-us.apache.org/repos/asf/karaf/repo
Commit: http://git-wip-us.apache.org/repos/asf/karaf/commit/232bf6c0
Tree: http://git-wip-us.apache.org/repos/asf/karaf/tree/232bf6c0
Diff: http://git-wip-us.apache.org/repos/asf/karaf/diff/232bf6c0
Branch: refs/heads/master
Commit: 232bf6c0406d127e705754cf0d0abbcb8389693f
Parents: 2a1ad29
Author: Guillaume Nodet <gn...@gmail.com>
Authored: Fri May 30 15:44:44 2014 +0200
Committer: Guillaume Nodet <gn...@gmail.com>
Committed: Fri May 30 15:44:44 2014 +0200
----------------------------------------------------------------------
jaas/modules/pom.xml | 6 +
.../jaas/modules/BackingEngineFactory.java | 7 +-
.../jaas/modules/jdbc/JDBCBackingEngine.java | 383 +++++++------------
.../modules/jdbc/JDBCBackingEngineFactory.java | 9 +-
.../jaas/modules/jdbc/JDBCLoginModule.java | 110 ++----
.../karaf/jaas/modules/jdbc/JDBCUtils.java | 95 ++++-
.../PropertiesBackingEngineFactory.java | 10 +-
.../jaas/modules/jdbc/JdbcLoginModuleTest.java | 236 ++++++++++++
pom.xml | 1 +
9 files changed, 497 insertions(+), 360 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/karaf/blob/232bf6c0/jaas/modules/pom.xml
----------------------------------------------------------------------
diff --git a/jaas/modules/pom.xml b/jaas/modules/pom.xml
index 76205ac..7302e99 100644
--- a/jaas/modules/pom.xml
+++ b/jaas/modules/pom.xml
@@ -100,6 +100,12 @@
<version>${directory-version}</version>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>org.apache.derby</groupId>
+ <artifactId>derby</artifactId>
+ <version>${derby-version}</version>
+ <scope>test</scope>
+ </dependency>
</dependencies>
<build>
http://git-wip-us.apache.org/repos/asf/karaf/blob/232bf6c0/jaas/modules/src/main/java/org/apache/karaf/jaas/modules/BackingEngineFactory.java
----------------------------------------------------------------------
diff --git a/jaas/modules/src/main/java/org/apache/karaf/jaas/modules/BackingEngineFactory.java b/jaas/modules/src/main/java/org/apache/karaf/jaas/modules/BackingEngineFactory.java
index 16fbb82..c7bb2cf 100644
--- a/jaas/modules/src/main/java/org/apache/karaf/jaas/modules/BackingEngineFactory.java
+++ b/jaas/modules/src/main/java/org/apache/karaf/jaas/modules/BackingEngineFactory.java
@@ -21,18 +21,13 @@ public interface BackingEngineFactory {
/**
* Returns the corresponding module class.
- *
- * @return
*/
String getModuleClass();
/**
* Backing engine factory method.
- *
- * @param options
- * @return
*/
- BackingEngine build(Map options);
+ BackingEngine build(Map<String,?> options);
}
http://git-wip-us.apache.org/repos/asf/karaf/blob/232bf6c0/jaas/modules/src/main/java/org/apache/karaf/jaas/modules/jdbc/JDBCBackingEngine.java
----------------------------------------------------------------------
diff --git a/jaas/modules/src/main/java/org/apache/karaf/jaas/modules/jdbc/JDBCBackingEngine.java b/jaas/modules/src/main/java/org/apache/karaf/jaas/modules/jdbc/JDBCBackingEngine.java
index 9723de8..189abd9 100644
--- a/jaas/modules/src/main/java/org/apache/karaf/jaas/modules/jdbc/JDBCBackingEngine.java
+++ b/jaas/modules/src/main/java/org/apache/karaf/jaas/modules/jdbc/JDBCBackingEngine.java
@@ -24,12 +24,14 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.sql.DataSource;
+
import java.security.Principal;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@@ -40,8 +42,6 @@ public class JDBCBackingEngine implements BackingEngine {
private DataSource dataSource;
private EncryptionSupport encryptionSupport;
- private static final String MSG_CONNECTION_CLOSE_FAILED = "Failed to clearly close connection to the database:";
-
private String addUserStatement = "INSERT INTO USERS VALUES(?,?)";
private String addRoleStatement = "INSERT INTO ROLES VALUES(?,?)";
private String deleteRoleStatement = "DELETE FROM ROLES WHERE USERNAME=? AND ROLE=?";
@@ -52,8 +52,6 @@ public class JDBCBackingEngine implements BackingEngine {
/**
* Constructor
- *
- * @param dataSource
*/
public JDBCBackingEngine(DataSource dataSource) {
this.dataSource = dataSource;
@@ -66,203 +64,90 @@ public class JDBCBackingEngine implements BackingEngine {
/**
* Adds a new user.
- *
- * @param username
- * @param password
*/
public void addUser(String username, String password) {
- Connection connection = null;
- PreparedStatement statement = null;
-
- String newPassword = password;
-
+ if (username.startsWith(GROUP_PREFIX)) {
+ throw new IllegalArgumentException("Prefix not permitted: " + GROUP_PREFIX);
+ }
//If encryption support is enabled, encrypt password
if (encryptionSupport != null && encryptionSupport.getEncryption() != null) {
- newPassword = encryptionSupport.getEncryption().encryptPassword(password);
+ password = encryptionSupport.getEncryption().encryptPassword(password);
if (encryptionSupport.getEncryptionPrefix() != null) {
- newPassword = encryptionSupport.getEncryptionPrefix() + newPassword;
+ password = encryptionSupport.getEncryptionPrefix() + password;
}
if (encryptionSupport.getEncryptionSuffix() != null) {
- newPassword = newPassword + encryptionSupport.getEncryptionSuffix();
+ password = password + encryptionSupport.getEncryptionSuffix();
}
}
-
- if (dataSource != null) {
-
- try {
- connection = dataSource.getConnection();
- statement = connection.prepareStatement(addUserStatement);
- statement.setString(1, username);
- statement.setString(2, newPassword);
- int rows = statement.executeUpdate();
-
- if (!connection.getAutoCommit()) {
- connection.commit();
- }
- if (logger.isDebugEnabled()) {
- logger.debug(String.format("Executiong [%s], USERNAME=%s, PASSWORD=%s. %i rows affected.", addUserStatement, username, newPassword, rows));
- }
- } catch (SQLException e) {
- logger.error("Error executiong statement", e);
- } finally {
- try {
- if (statement != null) {
- statement.close();
- }
- if (connection != null) {
- connection.close();
- }
- } catch (SQLException e) {
- logger.warn(MSG_CONNECTION_CLOSE_FAILED, e);
- }
+ try {
+ try (Connection connection = dataSource.getConnection()) {
+ rawUpdate(connection, addUserStatement, username, password);
}
+ } catch (SQLException e) {
+ throw new RuntimeException("Error adding user", e);
}
}
/**
* Delete user by username.
- *
- * @param username
*/
public void deleteUser(String username) {
- Connection connection = null;
- PreparedStatement userStatement = null;
- PreparedStatement roleStatement = null;
-
- if (dataSource != null) {
-
- try {
- connection = dataSource.getConnection();
-
- //Remove from roles
- roleStatement = connection.prepareStatement(deleteAllUserRolesStatement);
- roleStatement.setString(1, username);
- roleStatement.executeUpdate();
-
- //Remove from users
- userStatement = connection.prepareStatement(deleteUserStatement);
- userStatement.setString(1, username);
- int userRows = userStatement.executeUpdate();
-
+ try {
+ try (Connection connection = dataSource.getConnection()) {
+ rawUpdate(connection, deleteAllUserRolesStatement, username);
+ rawUpdate(connection, deleteUserStatement, username);
if (!connection.getAutoCommit()) {
connection.commit();
}
-
- if (logger.isDebugEnabled()) {
- logger.debug(String.format("Executiong [%s], USERNAME=%s. %i userRows affected.", deleteUserStatement, username, userRows));
- }
- } catch (SQLException e) {
- logger.error("Error executiong statement", e);
- } finally {
- try {
- if (userStatement != null) {
- userStatement.close();
- }
- if (roleStatement != null) {
- roleStatement.close();
- }
- if (connection != null) {
- connection.close();
- }
- } catch (SQLException e) {
- logger.warn(MSG_CONNECTION_CLOSE_FAILED, e);
- }
}
+ } catch (SQLException e) {
+ throw new RuntimeException("Error deleting user", e);
}
}
/**
* List all Users
- *
- * @return
*/
public List<UserPrincipal> listUsers() {
- List<UserPrincipal> users = new ArrayList<UserPrincipal>();
-
- Connection connection = null;
- PreparedStatement listUserStatement = null;
- ResultSet usersResultSet = null;
-
-
- if (dataSource != null) {
-
- try {
- connection = dataSource.getConnection();
-
- //Remove from users
- listUserStatement = connection.prepareStatement(selectUsersQuery);
- usersResultSet = listUserStatement.executeQuery();
- while (usersResultSet.next()) {
- String username = usersResultSet.getString("USERNAME");
- users.add(new UserPrincipal(username));
- }
- } catch (SQLException e) {
- logger.error("Error executiong statement", e);
- } finally {
- try {
- if (usersResultSet != null) {
- usersResultSet.close();
- }
- if (listUserStatement != null) {
- listUserStatement.close();
+ try {
+ try (Connection connection = dataSource.getConnection()) {
+ List<UserPrincipal> users = new ArrayList<>();
+ for (String name : rawSelect(connection, selectUsersQuery)) {
+ if (!name.startsWith(GROUP_PREFIX)) {
+ users.add(new UserPrincipal(name));
}
- if (connection != null) {
- connection.close();
- }
- } catch (SQLException e) {
- logger.warn(MSG_CONNECTION_CLOSE_FAILED, e);
}
+ return users;
}
+ } catch (SQLException e) {
+ throw new RuntimeException("Error listing users", e);
}
- return users;
}
/**
* List the roles of the {@param principal}.
- *
- * @param principal
- * @return
*/
public List<RolePrincipal> listRoles(Principal principal) {
- List<RolePrincipal> roles = new ArrayList<RolePrincipal>();
-
- Connection connection = null;
- PreparedStatement listRolesStatement = null;
- ResultSet rolesResultSet = null;
-
-
- if (dataSource != null) {
-
- try {
- connection = dataSource.getConnection();
-
- //Remove from roles
- listRolesStatement = connection.prepareStatement(selectRolesQuery);
- listRolesStatement.setString(1, principal.getName());
-
- rolesResultSet = listRolesStatement.executeQuery();
-
- while (rolesResultSet.next()) {
- String role = rolesResultSet.getString(1);
- roles.add(new RolePrincipal(role));
+ try {
+ try (Connection connection = dataSource.getConnection()) {
+ if (principal instanceof GroupPrincipal) {
+ return listRoles(connection, GROUP_PREFIX + principal.getName());
+ } else {
+ return listRoles(connection, principal.getName());
}
+ }
+ } catch (SQLException e) {
+ throw new RuntimeException("Error listing roles", e);
+ }
+ }
- } catch (SQLException e) {
- logger.error("Error executiong statement", e);
- } finally {
- try {
- if (rolesResultSet != null) {
- rolesResultSet.close();
- }
- if (listRolesStatement != null) {
- listRolesStatement.close();
- }
- if (connection != null) {
- connection.close();
- }
- } catch (SQLException e) {
- logger.warn(MSG_CONNECTION_CLOSE_FAILED, e);
- }
+ private List<RolePrincipal> listRoles(Connection connection, String name) throws SQLException {
+ List<RolePrincipal> roles = new ArrayList<>();
+ for (String role : rawSelect(connection, selectRolesQuery, name)) {
+ if (role.startsWith(GROUP_PREFIX)) {
+ roles.addAll(listRoles(connection, role));
+ } else {
+ roles.add(new RolePrincipal(role));
}
}
return roles;
@@ -270,88 +155,118 @@ public class JDBCBackingEngine implements BackingEngine {
/**
* Add a role to a user.
- *
- * @param username
- * @param role
*/
public void addRole(String username, String role) {
- Connection connection = null;
- PreparedStatement statement = null;
-
- if (dataSource != null) {
-
- try {
- connection = dataSource.getConnection();
- statement = connection.prepareStatement(addRoleStatement);
- statement.setString(1, username);
- statement.setString(2, role);
- int rows = statement.executeUpdate();
-
+ try {
+ try (Connection connection = dataSource.getConnection()) {
+ rawUpdate(connection, addRoleStatement, username, role);
if (!connection.getAutoCommit()) {
connection.commit();
}
- if (logger.isDebugEnabled()) {
- logger.debug(String.format("Executiong [%s], USERNAME=%s, ROLE=%s. %i rows affected.", addRoleStatement, username, role, rows));
- }
- } catch (SQLException e) {
- logger.error("Error executiong statement", e);
- } finally {
- try {
- if (statement != null) {
- statement.close();
- }
- if (connection != null) {
- connection.close();
- }
- } catch (SQLException e) {
- logger.warn(MSG_CONNECTION_CLOSE_FAILED, e);
- }
}
+ } catch (SQLException e) {
+ throw new RuntimeException("Error adding role", e);
}
}
/**
* Remove role from user.
- *
- * @param username
- * @param role
*/
public void deleteRole(String username, String role) {
- Connection connection = null;
- PreparedStatement statement = null;
-
- if (dataSource != null) {
+ try {
+ try (Connection connection = dataSource.getConnection()) {
+ rawUpdate(connection, deleteRoleStatement, username, role);
+ if (!connection.getAutoCommit()) {
+ connection.commit();
+ }
+ }
+ } catch (SQLException e) {
+ throw new RuntimeException("Error deleting role", e);
+ }
+ }
- try {
- connection = dataSource.getConnection();
- statement = connection.prepareStatement(deleteRoleStatement);
- statement.setString(1, username);
- statement.setString(2, role);
- int rows = statement.executeUpdate();
+ @Override
+ public List<GroupPrincipal> listGroups(UserPrincipal principal) {
+ try {
+ try (Connection connection = dataSource.getConnection()) {
+ List<GroupPrincipal> roles = new ArrayList<>();
+ for (String role : rawSelect(connection, selectRolesQuery, principal.getName())) {
+ if (role.startsWith(GROUP_PREFIX)) {
+ roles.add(new GroupPrincipal(role.substring(GROUP_PREFIX.length())));
+ }
+ }
+ return roles;
+ }
+ } catch (SQLException e) {
+ throw new RuntimeException("Error deleting role", e);
+ }
+ }
+ @Override
+ public void addGroup(String username, String group) {
+ try {
+ try (Connection connection = dataSource.getConnection()) {
+ String groupName = GROUP_PREFIX + group;
+ rawUpdate(connection, addRoleStatement, username, groupName);
if (!connection.getAutoCommit()) {
connection.commit();
}
- if (logger.isDebugEnabled()) {
- logger.debug(String.format("Executiong [%s], USERNAME=%s, ROLE=%s. %i rows affected.", deleteRoleStatement, username, role, rows));
- }
- } catch (SQLException e) {
- logger.error("Error executing statement", e);
- } finally {
- try {
- if (statement != null) {
- statement.close();
- }
- if (connection != null) {
- connection.close();
+ }
+ } catch (SQLException e) {
+ logger.error("Error executing statement", e);
+ }
+ }
+
+ @Override
+ public void deleteGroup(String username, String group) {
+ try {
+ try (Connection connection = dataSource.getConnection()) {
+ rawUpdate(connection, deleteRoleStatement, username, GROUP_PREFIX + group);
+ // garbage collection, clean up the groups if needed
+ boolean inUse = false;
+ for (String user : rawSelect(connection, selectUsersQuery)) {
+ for (String g : rawSelect(connection, selectRolesQuery, user)) {
+ if (group.equals(g)) {
+ // there is another user of this group, nothing to clean up
+ inUse = true;
+ break;
+ }
}
- } catch (SQLException e) {
- logger.warn(MSG_CONNECTION_CLOSE_FAILED, e);
+ }
+ // nobody is using this group any more, remove it
+ if (!inUse) {
+ rawUpdate(connection, deleteAllUserRolesStatement, GROUP_PREFIX + group);
+ }
+ if (!connection.getAutoCommit()) {
+ connection.commit();
}
}
+ } catch (SQLException e) {
+ logger.error("Error executing statement", e);
}
}
+ @Override
+ public void addGroupRole(String group, String role) {
+ addRole(GROUP_PREFIX + group, role);
+ }
+
+ @Override
+ public void deleteGroupRole(String group, String role) {
+ deleteRole(GROUP_PREFIX + group, role);
+ }
+
+ protected void rawUpdate(Connection connection, String query, String... params) throws SQLException {
+ int rows = JDBCUtils.rawUpdate(connection, query, params);
+ if (logger.isDebugEnabled()) {
+ logger.debug(String.format("Executing [%s], params=%s. %d rows affected.", query, Arrays.toString(params), rows));
+ }
+ }
+
+ protected List<String> rawSelect(Connection connection, String query, String... params) throws SQLException {
+ return JDBCUtils.rawSelect(connection, query, params);
+ }
+
public String getAddUserStatement() {
return addUserStatement;
}
@@ -408,34 +323,4 @@ public class JDBCBackingEngine implements BackingEngine {
this.selectRolesQuery = selectRolesQuery;
}
- @Override
- public List<GroupPrincipal> listGroups(UserPrincipal user) {
- // TODO support of groups has to be added
- return Collections.emptyList();
- }
-
- @Override
- public void addGroup(String username, String group) {
- // TODO support of groups has to be added
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void deleteGroup(String username, String group) {
- // TODO support of groups has to be added
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void addGroupRole(String group, String role) {
- // TODO support of groups has to be added
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void deleteGroupRole(String group, String role) {
- // TODO support of groups has to be added
- throw new UnsupportedOperationException();
- }
-
}
http://git-wip-us.apache.org/repos/asf/karaf/blob/232bf6c0/jaas/modules/src/main/java/org/apache/karaf/jaas/modules/jdbc/JDBCBackingEngineFactory.java
----------------------------------------------------------------------
diff --git a/jaas/modules/src/main/java/org/apache/karaf/jaas/modules/jdbc/JDBCBackingEngineFactory.java b/jaas/modules/src/main/java/org/apache/karaf/jaas/modules/jdbc/JDBCBackingEngineFactory.java
index f6d1e7e..7e0415a 100644
--- a/jaas/modules/src/main/java/org/apache/karaf/jaas/modules/jdbc/JDBCBackingEngineFactory.java
+++ b/jaas/modules/src/main/java/org/apache/karaf/jaas/modules/jdbc/JDBCBackingEngineFactory.java
@@ -32,11 +32,8 @@ public class JDBCBackingEngineFactory implements BackingEngineFactory {
/**
* Build a Backing engine for the JDBCLoginModule.
- *
- * @param options
- * @return
*/
- public BackingEngine build(Map options) {
+ public BackingEngine build(Map<String, ?> options) {
JDBCBackingEngine instance = null;
String datasourceURL = (String) options.get(JDBCUtils.DATASOURCE);
BundleContext bundleContext = (BundleContext) options.get(BundleContext.class.getName());
@@ -50,7 +47,7 @@ public class JDBCBackingEngineFactory implements BackingEngineFactory {
String selectRolesQuery = (String) options.get(JDBCLoginModule.ROLE_QUERY);
try {
- DataSource dataSource = (DataSource) JDBCUtils.createDatasource(bundleContext, datasourceURL);
+ DataSource dataSource = JDBCUtils.createDatasource(bundleContext, datasourceURL);
EncryptionSupport encryptionSupport = new EncryptionSupport(options);
instance = new JDBCBackingEngine(dataSource, encryptionSupport);
if(addUserStatement != null) {
@@ -82,8 +79,6 @@ public class JDBCBackingEngineFactory implements BackingEngineFactory {
/**
* Returns the login module class, that this factory can build.
- *
- * @return
*/
public String getModuleClass() {
return JDBCLoginModule.class.getName();
http://git-wip-us.apache.org/repos/asf/karaf/blob/232bf6c0/jaas/modules/src/main/java/org/apache/karaf/jaas/modules/jdbc/JDBCLoginModule.java
----------------------------------------------------------------------
diff --git a/jaas/modules/src/main/java/org/apache/karaf/jaas/modules/jdbc/JDBCLoginModule.java b/jaas/modules/src/main/java/org/apache/karaf/jaas/modules/jdbc/JDBCLoginModule.java
index ea81859..93255af 100644
--- a/jaas/modules/src/main/java/org/apache/karaf/jaas/modules/jdbc/JDBCLoginModule.java
+++ b/jaas/modules/src/main/java/org/apache/karaf/jaas/modules/jdbc/JDBCLoginModule.java
@@ -15,9 +15,11 @@
*/
package org.apache.karaf.jaas.modules.jdbc;
+import org.apache.karaf.jaas.boot.principal.GroupPrincipal;
import org.apache.karaf.jaas.boot.principal.RolePrincipal;
import org.apache.karaf.jaas.boot.principal.UserPrincipal;
import org.apache.karaf.jaas.modules.AbstractKarafLoginModule;
+import org.apache.karaf.jaas.modules.BackingEngine;
import org.apache.karaf.jaas.modules.properties.PropertiesLoginModule;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -34,6 +36,7 @@ import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashSet;
+import java.util.List;
import java.util.Map;
public class JDBCLoginModule extends AbstractKarafLoginModule {
@@ -56,24 +59,20 @@ public class JDBCLoginModule extends AbstractKarafLoginModule {
public void initialize(Subject subject, CallbackHandler callbackHandler, Map<String, ?> sharedState, Map<String, ?> options) {
super.initialize(subject, callbackHandler, options);
datasourceURL = (String) options.get(JDBCUtils.DATASOURCE);
- passwordQuery = (String) options.get(PASSWORD_QUERY);
- roleQuery = (String) options.get(ROLE_QUERY);
if (datasourceURL == null || datasourceURL.trim().length() == 0) {
LOGGER.error("No datasource was specified ");
} else if (!datasourceURL.startsWith(JDBCUtils.JNDI) && !datasourceURL.startsWith(JDBCUtils.OSGI)) {
LOGGER.error("Invalid datasource lookup protocol");
}
+ if (options.containsKey(PASSWORD_QUERY)) {
+ passwordQuery = (String) options.get(PASSWORD_QUERY);
+ }
+ if (options.containsKey(ROLE_QUERY)) {
+ roleQuery = (String) options.get(ROLE_QUERY);
+ }
}
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);
@@ -94,75 +93,42 @@ public class JDBCLoginModule extends AbstractKarafLoginModule {
}
String password = new String(tmpPassword);
- principals = new HashSet<Principal>();
+ principals = new HashSet<>();
try {
- Object credentialsDatasource = JDBCUtils.createDatasource(bundleContext, 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()) {
- if (!this.detailedLoginExcepion) {
- throw new LoginException("login failed");
- } else {
- throw new LoginException("User " + user + " does not exist");
- }
- } else {
- String storedPassword = passwordResultSet.getString(1);
-
- if (!checkPassword(password, storedPassword)) {
- if (!this.detailedLoginExcepion) {
- throw new LoginException("login failed");
- } else {
- throw new LoginException("Password for " + user + " does not match");
- }
+ DataSource datasource = JDBCUtils.createDatasource(bundleContext, datasourceURL);
+ try (Connection connection = datasource.getConnection()) {
+ List<String> passwords = JDBCUtils.rawSelect(connection, passwordQuery, user);
+ if (passwords.isEmpty()) {
+ if (!this.detailedLoginExcepion) {
+ throw new LoginException("login failed");
+ } else {
+ throw new LoginException("User " + user + " does not exist");
+ }
+ }
+ if (!checkPassword(password, passwords.get(0))) {
+ if (!this.detailedLoginExcepion) {
+ throw new LoginException("login failed");
+ } else {
+ throw new LoginException("Password for " + user + " does not match");
+ }
}
principals.add(new UserPrincipal(user));
- }
- //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 database:" + ex.getMessage());
- } finally {
- try {
- if (passwordResultSet != null) {
- passwordResultSet.close();
- }
- if (passwordStatement != null) {
- passwordStatement.close();
+ List<String> roles = JDBCUtils.rawSelect(connection, roleQuery, user);
+ for (String role : roles) {
+ if (role.startsWith(BackingEngine.GROUP_PREFIX)) {
+ principals.add(new GroupPrincipal(role.substring(BackingEngine.GROUP_PREFIX.length())));
+ for (String r : JDBCUtils.rawSelect(connection, roleQuery, role)) {
+ principals.add(new RolePrincipal(r));
+ }
+ } else {
+ principals.add(new RolePrincipal(role));
+ }
}
- if (roleResultSet != null) {
- roleResultSet.close();
- }
- if (roleStatement != null) {
- roleStatement.close();
- }
- if (connection != null) {
- connection.close();
- }
- } catch (SQLException ex) {
- LOGGER.warn("Failed to clearly close connection to the database:", ex);
}
+ } catch (Exception ex) {
+ throw new LoginException("Error has occurred while retrieving credentials from database:" + ex.getMessage());
}
return true;
}
http://git-wip-us.apache.org/repos/asf/karaf/blob/232bf6c0/jaas/modules/src/main/java/org/apache/karaf/jaas/modules/jdbc/JDBCUtils.java
----------------------------------------------------------------------
diff --git a/jaas/modules/src/main/java/org/apache/karaf/jaas/modules/jdbc/JDBCUtils.java b/jaas/modules/src/main/java/org/apache/karaf/jaas/modules/jdbc/JDBCUtils.java
index eaecfdd..c782abe 100644
--- a/jaas/modules/src/main/java/org/apache/karaf/jaas/modules/jdbc/JDBCUtils.java
+++ b/jaas/modules/src/main/java/org/apache/karaf/jaas/modules/jdbc/JDBCUtils.java
@@ -16,10 +16,19 @@
package org.apache.karaf.jaas.modules.jdbc;
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
import javax.naming.InitialContext;
+import javax.sql.DataSource;
public final class JDBCUtils {
@@ -33,32 +42,37 @@ public final class JDBCUtils {
/**
* Looks up a datasource from the url. The datasource can be passed either as jndi name or bundles ldap filter.
- *
- * @param url
- * @return
- * @throws Exception
*/
- public static Object createDatasource(BundleContext bc, String url) throws Exception {
- if (url == null) {
- throw new Exception("Illegal datasource url format. Datasource URL cannot be null.");
- } else if (url.trim().length() == 0) {
- throw new Exception("Illegal datasource url format. Datasource URL cannot be empty.");
+ public static DataSource createDatasource(BundleContext bc, String url) throws Exception {
+ Object ds = doCreateDatasource(bc, url);
+ if (ds == null) {
+ throw new Exception("Unable to create datasource for " + url);
+ }
+ return DataSource.class.cast(ds);
+ }
+
+ protected static Object doCreateDatasource(BundleContext bc, String url) throws Exception {
+ url = (url != null) ? url.trim() : null;
+ if (url == null || url.isEmpty()) {
+ throw new Exception("Illegal datasource url format. Datasource URL cannot be null or empty.");
} else if (url.startsWith(JNDI)) {
String jndiName = url.substring(JNDI.length());
InitialContext ic = new InitialContext();
- return ic.lookup(jndiName);
+ try {
+ return ic.lookup(jndiName);
+ } finally {
+ ic.close();
+ }
} 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];
- }
+ if (tokens.length > 0) {
+ clazz = tokens[0];
+ }
+ if (tokens.length > 1) {
+ filter = tokens[1];
}
ServiceReference[] references = bc.getServiceReferences(clazz, filter);
if (references != null) {
@@ -70,8 +84,53 @@ public final class JDBCUtils {
throw new Exception("Unable to find service reference for datasource: " + clazz + "/" + filter);
}
} else {
- throw new Exception("Illegal datasource url format");
+ throw new Exception("Illegal datasource url format " + url);
+ }
+ }
+
+ protected static int rawUpdate(DataSource dataSource, String query, String... params) throws SQLException {
+ try (Connection connection = dataSource.getConnection()) {
+ try (PreparedStatement statement = connection.prepareStatement(query)) {
+ for (int i = 0; i < params.length; i++) {
+ statement.setString(i + 1, params[i]);
+ }
+ int res = statement.executeUpdate();
+ if (!connection.getAutoCommit()) {
+ connection.commit();
+ }
+ return res;
+ }
+ }
+ }
+
+ protected static int rawUpdate(Connection connection, String query, String... params) throws SQLException {
+ try (PreparedStatement statement = connection.prepareStatement(query)) {
+ for (int i = 0; i < params.length; i++) {
+ statement.setString(i + 1, params[i]);
+ }
+ return statement.executeUpdate();
+ }
+ }
+
+ protected static List<String> rawSelect(DataSource dataSource, String query, String... params) throws SQLException {
+ try (Connection connection = dataSource.getConnection()) {
+ return rawSelect(connection, query, params);
+ }
+ }
+
+ protected static List<String> rawSelect(Connection connection, String query, String... params) throws SQLException {
+ List<String> results = new ArrayList<>();
+ try (PreparedStatement statement = connection.prepareStatement(query)) {
+ for (int i = 0; i < params.length; i++) {
+ statement.setString(i + 1, params[i]);
+ }
+ try (ResultSet resultSet = statement.executeQuery()) {
+ while (resultSet.next()) {
+ results.add(resultSet.getString(1));
+ }
+ }
}
+ return results;
}
}
http://git-wip-us.apache.org/repos/asf/karaf/blob/232bf6c0/jaas/modules/src/main/java/org/apache/karaf/jaas/modules/properties/PropertiesBackingEngineFactory.java
----------------------------------------------------------------------
diff --git a/jaas/modules/src/main/java/org/apache/karaf/jaas/modules/properties/PropertiesBackingEngineFactory.java b/jaas/modules/src/main/java/org/apache/karaf/jaas/modules/properties/PropertiesBackingEngineFactory.java
index df8b5f9..dd583b4 100644
--- a/jaas/modules/src/main/java/org/apache/karaf/jaas/modules/properties/PropertiesBackingEngineFactory.java
+++ b/jaas/modules/src/main/java/org/apache/karaf/jaas/modules/properties/PropertiesBackingEngineFactory.java
@@ -35,11 +35,8 @@ public class PropertiesBackingEngineFactory implements BackingEngineFactory {
/**
* Builds the Backing Engine
- *
- * @param options
- * @return
*/
- public BackingEngine build(Map options) {
+ public BackingEngine build(Map<String,?> options) {
PropertiesBackingEngine engine = null;
String usersFile = (String) options.get(USER_FILE);
@@ -51,15 +48,12 @@ public class PropertiesBackingEngineFactory implements BackingEngineFactory {
engine = new PropertiesBackingEngine(users, encryptionSupport);
} catch (IOException ioe) {
LOGGER.warn("Cannot open users file: {}", usersFile);
- } finally {
- return engine;
}
+ return engine;
}
/**
* Returns the login module class, that this factory can build.
- *
- * @return
*/
public String getModuleClass() {
return PropertiesLoginModule.class.getName();
http://git-wip-us.apache.org/repos/asf/karaf/blob/232bf6c0/jaas/modules/src/test/java/org/apache/karaf/jaas/modules/jdbc/JdbcLoginModuleTest.java
----------------------------------------------------------------------
diff --git a/jaas/modules/src/test/java/org/apache/karaf/jaas/modules/jdbc/JdbcLoginModuleTest.java b/jaas/modules/src/test/java/org/apache/karaf/jaas/modules/jdbc/JdbcLoginModuleTest.java
new file mode 100644
index 0000000..24634dc
--- /dev/null
+++ b/jaas/modules/src/test/java/org/apache/karaf/jaas/modules/jdbc/JdbcLoginModuleTest.java
@@ -0,0 +1,236 @@
+/*
+ *
+ * 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.sql.Connection;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.HashMap;
+import java.util.Map;
+
+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.sql.DataSource;
+
+import org.apache.derby.jdbc.EmbeddedDataSource40;
+import org.apache.karaf.jaas.boot.principal.GroupPrincipal;
+import org.apache.karaf.jaas.boot.principal.RolePrincipal;
+import org.apache.karaf.jaas.boot.principal.UserPrincipal;
+import org.easymock.EasyMock;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+
+import static org.easymock.EasyMock.expect;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+public class JdbcLoginModuleTest {
+
+ private EmbeddedDataSource40 dataSource;
+ private Map<String, Object> options;
+
+ @Before
+ public void setUp() throws Exception {
+ System.setProperty("derby.stream.error.file", "target/derby.log");
+
+ // Create datasource
+ dataSource = new EmbeddedDataSource40();
+ dataSource.setDatabaseName("memory:db");
+ dataSource.setCreateDatabase("create");
+
+ // Delete tables
+ try (Connection connection = dataSource.getConnection()) {
+ connection.setAutoCommit(true);
+ try {
+ try (Statement statement = connection.createStatement()) {
+ statement.execute("drop table USERS");
+ }
+ } catch (SQLException e) {
+ // Ignore
+ }
+ try {
+ try (Statement statement = connection.createStatement()) {
+ statement.execute("drop table ROLES");
+ }
+ } catch (SQLException e) {
+ // Ignore
+ }
+ connection.commit();
+ }
+
+ // Create tables
+ try (Connection connection = dataSource.getConnection()) {
+ try (Statement statement = connection.createStatement()) {
+ statement.execute("create table USERS (USERNAME VARCHAR(32) PRIMARY KEY, PASSWORD VARCHAR(32))");
+ }
+ try (Statement statement = connection.createStatement()) {
+ statement.execute("create table ROLES (USERNAME VARCHAR(32), ROLE VARCHAR(1024))");
+ }
+ connection.commit();
+ }
+
+ // Mocks
+ BundleContext context = EasyMock.createMock(BundleContext.class);
+ ServiceReference reference = EasyMock.createMock(ServiceReference.class);
+
+ // Create options
+ options = new HashMap<>();
+ options.put(JDBCUtils.DATASOURCE, "osgi:" + DataSource.class.getName());
+ options.put(BundleContext.class.getName(), context);
+
+ expect(context.getServiceReferences(DataSource.class.getName(), null)).andReturn(new ServiceReference[] { reference });
+ expect(context.getService(reference)).andReturn(dataSource);
+ expect(context.ungetService(reference)).andReturn(true);
+
+ EasyMock.replay(context);
+ }
+
+ @Test
+ public void testLoginModule() throws Exception {
+ JDBCBackingEngine engine = new JDBCBackingEngine(dataSource);
+ engine.addUser("abc", "xyz");
+ engine.addRole("abc", "role1");
+
+ JDBCLoginModule module = new JDBCLoginModule();
+
+ Subject subject = new Subject();
+ module.initialize(subject, getCallbackHandler("abc", "xyz"), null, options);
+
+ module.login();
+ module.commit();
+
+ assertFalse(subject.getPrincipals(UserPrincipal.class).isEmpty());
+ assertEquals("abc", subject.getPrincipals(UserPrincipal.class).iterator().next().getName());
+ assertFalse(subject.getPrincipals(RolePrincipal.class).isEmpty());
+ assertEquals("role1", subject.getPrincipals(RolePrincipal.class).iterator().next().getName());
+ }
+
+ @Test
+ public void testLoginModuleWithGroups() throws Exception {
+ JDBCBackingEngine engine = new JDBCBackingEngine(dataSource);
+ engine.addGroupRole("group1", "role2");
+ engine.addUser("abc", "xyz");
+ engine.addRole("abc", "role1");
+ engine.addGroup("abc", "group1");
+
+ JDBCLoginModule module = new JDBCLoginModule();
+
+ Subject subject = new Subject();
+ module.initialize(subject, getCallbackHandler("abc", "xyz"), null, options);
+
+ module.login();
+ module.commit();
+
+ assertTrue(subject.getPrincipals().contains(new UserPrincipal("abc")));
+ assertTrue(subject.getPrincipals().contains(new GroupPrincipal("group1")));
+ assertTrue(subject.getPrincipals().contains(new RolePrincipal("role1")));
+ assertTrue(subject.getPrincipals().contains(new RolePrincipal("role2")));
+ }
+
+ @Test
+ public void testEngine() throws Exception {
+ JDBCBackingEngine engine = new JDBCBackingEngine(dataSource);
+
+ assertTrue(engine.listUsers().isEmpty());
+
+ engine.addUser("abc", "xyz");
+
+ assertTrue(engine.listUsers().contains(new UserPrincipal("abc")));
+ assertTrue(engine.listRoles(new UserPrincipal("abc")).isEmpty());
+ assertTrue(engine.listRoles(new GroupPrincipal("group1")).isEmpty());
+ assertTrue(engine.listGroups(new UserPrincipal("abc")).isEmpty());
+
+ engine.addRole("abc", "role1");
+
+ assertTrue(engine.listUsers().contains(new UserPrincipal("abc")));
+ assertTrue(engine.listRoles(new UserPrincipal("abc")).contains(new RolePrincipal("role1")));
+ assertTrue(engine.listRoles(new GroupPrincipal("group1")).isEmpty());
+ assertTrue(engine.listGroups(new UserPrincipal("abc")).isEmpty());
+
+ engine.addGroupRole("group1", "role2");
+
+ assertTrue(engine.listUsers().contains(new UserPrincipal("abc")));
+ assertTrue(engine.listRoles(new UserPrincipal("abc")).contains(new RolePrincipal("role1")));
+ assertTrue(engine.listRoles(new GroupPrincipal("group1")).contains(new RolePrincipal("role2")));
+ assertTrue(engine.listGroups(new UserPrincipal("abc")).isEmpty());
+
+ engine.addGroup("abc", "group1");
+
+ assertTrue(engine.listUsers().contains(new UserPrincipal("abc")));
+ assertTrue(engine.listRoles(new UserPrincipal("abc")).contains(new RolePrincipal("role1")));
+ assertTrue(engine.listRoles(new UserPrincipal("abc")).contains(new RolePrincipal("role2")));
+ assertTrue(engine.listRoles(new GroupPrincipal("group1")).contains(new RolePrincipal("role2")));
+ assertTrue(engine.listGroups(new UserPrincipal("abc")).contains(new GroupPrincipal("group1")));
+
+ engine.deleteRole("abc", "role1");
+
+ assertTrue(engine.listUsers().contains(new UserPrincipal("abc")));
+ assertTrue(engine.listRoles(new UserPrincipal("abc")).contains(new RolePrincipal("role2")));
+ assertTrue(engine.listRoles(new GroupPrincipal("group1")).contains(new RolePrincipal("role2")));
+ assertTrue(engine.listGroups(new UserPrincipal("abc")).contains(new GroupPrincipal("group1")));
+
+ engine.deleteGroupRole("group1", "role2");
+
+ assertTrue(engine.listUsers().contains(new UserPrincipal("abc")));
+ assertTrue(engine.listRoles(new UserPrincipal("abc")).isEmpty());
+ assertTrue(engine.listRoles(new GroupPrincipal("group1")).isEmpty());
+ assertTrue(engine.listGroups(new UserPrincipal("abc")).contains(new GroupPrincipal("group1")));
+
+ engine.addGroupRole("group1", "role3");
+
+ assertTrue(engine.listUsers().contains(new UserPrincipal("abc")));
+ assertTrue(engine.listRoles(new UserPrincipal("abc")).contains(new RolePrincipal("role3")));
+ assertTrue(engine.listRoles(new GroupPrincipal("group1")).contains(new RolePrincipal("role3")));
+ assertTrue(engine.listGroups(new UserPrincipal("abc")).contains(new GroupPrincipal("group1")));
+
+ engine.deleteGroup("abc", "group1");
+
+ assertTrue(engine.listUsers().contains(new UserPrincipal("abc")));
+ assertTrue(engine.listRoles(new UserPrincipal("abc")).isEmpty());
+ assertTrue(engine.listRoles(new GroupPrincipal("group1")).isEmpty());
+ assertTrue(engine.listGroups(new UserPrincipal("abc")).isEmpty());
+
+ engine.deleteUser("abc");
+
+ assertTrue(engine.listUsers().isEmpty());
+ assertTrue(engine.listRoles(new UserPrincipal("abc")).isEmpty());
+ assertTrue(engine.listRoles(new GroupPrincipal("group1")).isEmpty());
+ assertTrue(engine.listGroups(new UserPrincipal("abc")).isEmpty());
+ }
+
+ private CallbackHandler getCallbackHandler(final String user, final String password) {
+ return new CallbackHandler() {
+ @Override
+ public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
+ for (Callback cb : callbacks) {
+ if (cb instanceof NameCallback) {
+ ((NameCallback) cb).setName(user);
+ } else if (cb instanceof PasswordCallback) {
+ ((PasswordCallback) cb).setPassword(password.toCharArray());
+ }
+ }
+ }
+ };
+ }
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/232bf6c0/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index fe89cb4..3a7747e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -249,6 +249,7 @@
<spring.security31.version>3.1.4.RELEASE</spring.security31.version>
<sshd.version>0.11.0</sshd.version>
+ <derby-version>10.10.1.1</derby-version>
<directory-version>2.0.0-M16</directory-version>
<struts.bundle.version>1.3.10_1</struts.bundle.version>
<xbean.version>3.16</xbean.version>