Default id provider is made less JBoss dependent. Tenant info is now put as group in security context with tenant as CSpaceTenant group-memeber
Common depends on authn service (for CSpaceTenant)
Account throws 400 if tenant and/or userid are missing. Provisioned test account with tenant association for testing purposes. Added account tests for the same.
Account client now packages all required classes. Used in authentication service tests.
Servicecontext now retrieves one or more tenants from security context before retrieving bindings. Still uses one tenant only (needs consumer to send tenant info if user is associated with n tenants. Client test now recognizes 401 for all service operations.
tests: service tests. account (new) tests. authn tests by enabling service side security
M services/authentication/service/src/main/java/org/collectionspace/authentication/CSpaceDBLoginModule.java
A services/authentication/service/src/main/java/org/collectionspace/authentication/DatabaseRealm.java
A services/authentication/service/src/main/java/org/collectionspace/authentication/CSpaceTenant.java
M services/authentication/service/src/main/resources/config/jboss-login-config.xml
M services/authentication/service/pom.xml
M services/authentication/jaxb/src/main/resources/authentication_identity_provider.xsd
M services/authentication/jaxb/pom.xml
M services/authentication/client/src/test/java/org/collectionspace/services/authentication/client/AuthenticationServiceTest.java
M services/authentication/client/src/main/resources/db/mysql/test_authn.sql
M services/authentication/client/src/main/resources/db/mysql/authentication.sql
M services/authentication/client/pom.xml
M services/JaxRsServiceProvider/src/main/resources/META-INF/persistence.xml
_M services/dimension/service
_M services/dimension/jaxb
M services/common/src/main/java/org/collectionspace/services/common/context/ServiceContext.java
M services/common/src/main/java/org/collectionspace/services/common/context/AbstractServiceContext.java
M services/common/pom.xml
M services/pom.xml
M services/account/service/src/main/java/org/collectionspace/services/account/storage/AccountStorageClient.java
M services/account/service/src/main/java/org/collectionspace/services/account/storage/AccountDocumentHandler.java
M services/account/service/src/main/java/org/collectionspace/services/account/AccountResource.java
M services/account/service/pom.xml
M services/account/jaxb/src/main/resources/accounts_common.xsd
A services/account/client/src/test/java/org/collectionspace/services/account
A services/account/client/src/test/java/org/collectionspace/services/account/client
A services/account/client/src/test/java/org/collectionspace/services/account/client/test
A + services/account/client/src/test/java/org/collectionspace/services/account/client/test/AccountTest.java
A + services/account/client/src/test/java/org/collectionspace/services/account/client/test/AccountServiceTest.java
D services/account/client/src/test/java/org/collectionspace/services/client/test/AccountTest.java
D services/account/client/src/test/java/org/collectionspace/services/client/test/AccountServiceTest.java
D services/account/client/src/test/java/org/collectionspace/services/client/AccountClient.java
D services/account/client/src/test/java/org/collectionspace/services/client/AccountProxy.java
M services/account/client/src/test/resources/META-INF/persistence.xml
M services/account/client/src/test/resources/log4j.properties
A + services/account/client/src/main/java/org/collectionspace/services/client/AccountClient.java
A + services/account/client/src/main/java/org/collectionspace/services/client/AccountProxy.java
A services/account/client/src/main/resources/db/mysql/test_account.sql
M services/account/client/src/main/resources/db/mysql/account.sql
M services/account/client/pom.xml
M services/account/client/build.xml
M services/build.xml
M services/client/src/main/java/org/collectionspace/services/client/test/AbstractServiceTest.java
M services/client/src/main/java/org/collectionspace/services/client/test/ServiceRequestType.java
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<persistence version="1.0" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd
-http://java.sun.com/xml/ns/persistence/orm http://java.sun.com/xml/ns/persistence/orm_1_0.xsd" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:orm="http://java.sun.com/xml/ns/persistence/orm" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ http://java.sun.com/xml/ns/persistence/orm http://java.sun.com/xml/ns/persistence/orm_1_0.xsd" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:orm="http://java.sun.com/xml/ns/persistence/orm" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<persistence-unit name="org.collectionspace.services">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<non-jta-data-source>CspaceDS</non-jta-data-source>
<class>org.collectionspace.services.account.AccountsCommon</class>
+ <class>org.collectionspace.services.account.AccountsCommon$Tenant</class>
<class>org.collectionspace.services.account.AccountsCommonList</class>
<class>org.collectionspace.services.account.AccountsCommonList$AccountListItem</class>
<class>org.collectionspace.services.authentication.User</class>
<class>org.collectionspace.services.authentication.Role</class>
<class>org.collectionspace.services.authentication.UserRole</class>
+
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect"/>
<property name="hibernate.max_fetch_depth" value="3"/>
<description>\r
collectionspace account service\r
</description>\r
- <!-- set global properties for this build -->\r
+ <!-- set global properties for this build -->\r
<property name="services.trunk" value="../../.."/>\r
<!-- enviornment should be declared before reading build.properties -->\r
<property environment="env" />\r
</condition>\r
\r
<target name="init">\r
- <!-- Create the time stamp -->\r
+ <!-- Create the time stamp -->\r
<tstamp/>\r
</target>\r
\r
\r
<target name="package" depends="package-unix,package-windows"\r
- description="Package CollectionSpace Services" />\r
+ description="Package CollectionSpace Services" />\r
<target name="package-unix" if="osfamily-unix">\r
<exec executable="mvn" failonerror="true">\r
<arg value="package" />\r
</target>\r
\r
<target name="install" depends="package,install-unix,install-windows"\r
- description="Install" />\r
+ description="Install" />\r
<target name="install-unix" if="osfamily-unix">\r
<exec executable="mvn" failonerror="true">\r
<arg value="install" />\r
<arg value="${mvn.opts}" />\r
</exec>\r
</target>\r
- \r
+\r
<target name="clean" depends="clean-unix,clean-windows"\r
- description="Delete target directories" >\r
+ description="Delete target directories" >\r
<delete dir="${build}"/>\r
</target>\r
<target name="clean-unix" if="osfamily-unix">\r
</target>\r
\r
<target name="gen_ddl" depends="gen_ddl-unix,gen_ddl-windows"\r
- description="geneate ddl" />\r
+ description="geneate ddl" />\r
<target name="gen_ddl-unix" if="osfamily-unix" depends="setup_hibernate.cfg">\r
<exec executable="mvn" failonerror="true">\r
<arg value="-Pddl" />\r
</target>\r
\r
<target name="create_db"\r
- description="create tables(s), indices for account service">\r
+ description="create tables(s), indices for account service">\r
+ <sql driver="com.mysql.jdbc.Driver"\r
+ url="jdbc:mysql://${db.host}:${db.port}/cspace"\r
+ userid="${db.user}"\r
+ password="${db.user.password}"\r
+ src="${db.script.dir}/account.sql"\r
+ >\r
+ <classpath>\r
+ <pathelement path="${db.driver.jar}"/>\r
+ </classpath>\r
+ </sql>\r
<sql driver="com.mysql.jdbc.Driver"\r
- url="jdbc:mysql://${db.host}:${db.port}/cspace"\r
- userid="${db.user}"\r
- password="${db.user.password}"\r
- src="${db.script.dir}/account.sql"\r
- >\r
+ url="jdbc:mysql://${db.host}:${db.port}/cspace"\r
+ userid="${db.user}"\r
+ password="${db.user.password}"\r
+ src="${db.script.dir}/test_account.sql"\r
+ >\r
<classpath>\r
<pathelement path="${db.driver.jar}"/>\r
</classpath>\r
</sql>\r
</target>\r
<target name="deploy" depends="install"\r
- description="deploy account service in ${jboss.server.cspace}">\r
+ description="deploy account service in ${jboss.server.cspace}">\r
<copy todir="${jboss.server.cspace}/cspace/services">\r
<fileset dir="${src}/main/resources/"/>\r
</copy>\r
</target>\r
\r
<target name="undeploy"\r
- description="undeploy account service from ${jboss.server.cspace}">\r
+ description="undeploy account service from ${jboss.server.cspace}">\r
</target>\r
\r
<target name="dist"\r
- description="generate distribution for account service" depends="package">\r
+ description="generate distribution for account service" depends="package">\r
<!-- copy db scripts, etc. -->\r
<copy todir="${services.trunk}/${dist.server.cspace}/cspace/services">\r
<fileset dir="${src}/main/resources/"/>\r
<?xml version="1.0" encoding="UTF-8"?>\r
<project xmlns="http://maven.apache.org/POM/4.0.0"\r
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"\r
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">\r
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"\r
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">\r
\r
<parent>\r
<artifactId>org.collectionspace.services.account</artifactId>\r
<artifactId>org.collectionspace.services.client</artifactId>\r
<version>1.0</version>\r
</dependency>\r
-<!-- Needed if/when client test framework files are moved into\r
+ <!-- Needed if/when client test framework files are moved into\r
/services/client/src/test from /services/client/src/main --> \r
<!-- <dependency>\r
<groupId>org.collectionspace.services</groupId>\r
<scope>test</scope>\r
<type>test-jar</type>\r
</dependency>-->\r
- \r
+\r
<dependency>\r
<groupId>org.testng</groupId>\r
<artifactId>testng</artifactId>\r
<artifactId>mysql-connector-java</artifactId>\r
</dependency>\r
</dependencies>\r
- \r
+\r
<build>\r
<finalName>cspace-services-account-client</finalName>\r
<plugins>\r
+alter table tenants drop foreign key FKAAE82D09C4F08FD6;
drop table if exists accounts_common;
-create table accounts_common (csid varchar(255) not null, email longtext not null, first_name longtext not null, last_name longtext not null, mi varchar(1), mobile varchar(255), phone varchar(255), screen_name varchar(128) not null, status varchar(15) not null, tenantid varchar(255) not null, userid longtext not null, primary key (csid));
+drop table if exists tenants;
+create table accounts_common (csid varchar(255) not null, email longtext not null, mobile varchar(255), phone varchar(255), screen_name varchar(128) not null, status varchar(15) not null, userid longtext not null, primary key (csid));
+create table tenants (HJID bigint not null auto_increment, id varchar(255) not null, name varchar(255) not null, TENANT_ACCOUNTSCOMMON_CSID varchar(255), primary key (HJID));
+alter table tenants add index FKAAE82D09C4F08FD6 (TENANT_ACCOUNTSCOMMON_CSID), add constraint FKAAE82D09C4F08FD6 foreign key (TENANT_ACCOUNTSCOMMON_CSID) references accounts_common (csid);
--- /dev/null
+--
+-- Copyright 2009 University of California at Berkeley
+-- Licensed under the Educational Community License (ECL), Version 2.0.
+-- You may not use this file except in compliance with this License.
+--
+use cspace;
+INSERT INTO `cspace`.`accounts_common` VALUES ('eeca40d7-dc77-4cc5-b489-16a53c75525a','test.test@berkeley.edu',NULL,NULL,'test','ACTIVE','test');
+
+INSERT INTO `cspace`.`tenants` VALUES (1,'1','movingimages.us','eeca40d7-dc77-4cc5-b489-16a53c75525a');
\ No newline at end of file
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.collectionspace.services.client.test;
+package org.collectionspace.services.account.client.test;
+import java.util.ArrayList;
import java.util.List;
+import java.util.UUID;
import javax.ws.rs.core.Response;
import org.apache.commons.codec.binary.Base64;
import org.collectionspace.services.account.AccountsCommon;
import org.collectionspace.services.account.AccountsCommonList;
import org.collectionspace.services.account.Status;
+import org.collectionspace.services.client.test.AbstractServiceTest;
+import org.collectionspace.services.client.test.ServiceRequestType;
import org.jboss.resteasy.client.ClientResponse;
import org.testng.Assert;
// Submit the request to the service and store the response.
AccountsCommon account =
- createAccountInstance("barney", "dino", "barney", "hithere08", "barney@dinoland.com");
+ createAccountInstance("barney", "hithere08", "barney@dinoland.com", true, true, true);
ClientResponse<Response> res = client.create(account);
int statusCode = res.getStatus();
}
}
+ @Test(dataProvider = "testName", dataProviderClass = AbstractServiceTest.class,
+ dependsOnMethods = {"create"})
+ public void createWithoutTenant(String testName) throws Exception {
+
+ setupCreate(testName);
+
+ // Submit the request to the service and store the response.
+ AccountsCommon account =
+ createAccountInstance("babybop", "hithere08", "babybop@dinoland.com", false, true, true);
+ ClientResponse<Response> res = client.create(account);
+ int statusCode = res.getStatus();
+ // Does it exactly match the expected status code?
+ if (logger.isDebugEnabled()) {
+ logger.debug(testName + ": status = " + statusCode);
+ }
+ Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
+ invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
+ Assert.assertEquals(statusCode, Response.Status.BAD_REQUEST.getStatusCode());
+
+ }
+
+ @Test(dataProvider = "testName", dataProviderClass = AbstractServiceTest.class,
+ dependsOnMethods = {"create"})
+ public void createWithoutUser(String testName) throws Exception {
+
+ setupCreate(testName);
+
+ // Submit the request to the service and store the response.
+ AccountsCommon account =
+ createAccountInstance("babybop", "hithere08", "babybop@dinoland.com", true, false, true);
+ ClientResponse<Response> res = client.create(account);
+ int statusCode = res.getStatus();
+ // Does it exactly match the expected status code?
+ if (logger.isDebugEnabled()) {
+ logger.debug(testName + ": status = " + statusCode);
+ }
+ Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
+ invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
+ Assert.assertEquals(statusCode, Response.Status.BAD_REQUEST.getStatusCode());
+ }
+
//to not cause uniqueness violation for account, createList is removed
@Override
@Test(dataProvider = "testName", dataProviderClass = AbstractServiceTest.class,
int i = 0;
for (AccountsCommonList.AccountListItem item : items) {
- logger.debug(testName + ": list-item[" + i + "] csid=" +
- item.getCsid());
- logger.debug(testName + ": list-item[" + i + "] screenName=" +
- item.getScreenName());
- logger.debug(testName + ": list-item[" + i + "] URI=" +
- item.getUri());
+ logger.debug(testName + ": list-item[" + i + "] csid="
+ + item.getCsid());
+ logger.debug(testName + ": list-item[" + i + "] screenName="
+ + item.getScreenName());
+ logger.debug(testName + ": list-item[" + i + "] URI="
+ + item.getUri());
i++;
}
Assert.assertEquals(res.getStatus(), EXPECTED_STATUS_CODE);
if (logger.isDebugEnabled()) {
- logger.debug("got object to update with ID: " + knownResourceId);
+ logger.debug(testName + ": got object to update password with ID: " + knownResourceId);
}
AccountsCommon toUpdateAccount =
(AccountsCommon) res.getEntity();
//change password
toUpdateAccount.setPassword(Base64.encodeBase64("imagination".getBytes()));
if (logger.isDebugEnabled()) {
- logger.debug("updated object");
+ logger.debug(testName + ": updated object");
logger.debug(objectAsXmlString(toUpdateAccount,
AccountsCommon.class));
}
}
@Test(dataProvider = "testName", dataProviderClass = AbstractServiceTest.class,
- dependsOnMethods = {"updatePassword"})
+ dependsOnMethods = {"update"})
+ public void updatePasswordWithoutUser(String testName) throws Exception {
+
+ // Perform setup.
+ setupUpdate(testName);
+
+ ClientResponse<AccountsCommon> res =
+ client.read(knownResourceId);
+ if (logger.isDebugEnabled()) {
+ logger.debug(testName + ": read status = " + res.getStatus());
+ }
+ Assert.assertEquals(res.getStatus(), EXPECTED_STATUS_CODE);
+
+ if (logger.isDebugEnabled()) {
+ logger.debug(testName + " : got object to update with ID: " + knownResourceId);
+ }
+ AccountsCommon toUpdateAccount =
+ (AccountsCommon) res.getEntity();
+ Assert.assertNotNull(toUpdateAccount);
+
+ toUpdateAccount.setUserId(null);
+ //change password
+ toUpdateAccount.setPassword(Base64.encodeBase64("imagination".getBytes()));
+ if (logger.isDebugEnabled()) {
+ logger.debug(testName + " : updated object");
+ logger.debug(objectAsXmlString(toUpdateAccount,
+ AccountsCommon.class));
+ }
+
+ // Submit the request to the service and store the response.
+ res = client.update(knownResourceId, toUpdateAccount);
+ int statusCode = res.getStatus();
+ // Check the status code of the response: does it match the expected response(s)?
+ if (logger.isDebugEnabled()) {
+ logger.debug(testName + ": status = " + statusCode);
+ }
+ Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
+ invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
+ Assert.assertEquals(statusCode, Response.Status.BAD_REQUEST.getStatusCode());
+
+ }
+
+ @Test(dataProvider = "testName", dataProviderClass = AbstractServiceTest.class,
+ dependsOnMethods = {"updatePasswordWithoutUser"})
public void deactivate(String testName) throws Exception {
// Perform setup.
// Note: The ID used in this 'create' call may be arbitrary.
// The only relevant ID may be the one used in updateAccount(), below.
AccountsCommon account =
- createAccountInstance("simba", "mufasa", "simba", "tiger", "simba@lionking.com");
+ createAccountInstance("simba", "tiger", "simba@lionking.com", true, true, true);
ClientResponse<AccountsCommon> res =
client.update(NON_EXISTENT_ID, account);
int statusCode = res.getStatus();
//
// Note: The ID used in this 'create' call may be arbitrary.
// The only relevant ID may be the one used in updateAccount(), below.
- ClientResponse<AccountsCommon> res =
+ ClientResponse<AccountsCommon> res =
client.read(knownResourceId);
if (logger.isDebugEnabled()) {
logger.debug(testName + ": read status = " + res.getStatus());
logger.debug(objectAsXmlString(toUpdateAccount,
AccountsCommon.class));
}
- EXPECTED_STATUS_CODE = Response.Status.BAD_REQUEST.getStatusCode();
+
res = client.update(knownResourceId, toUpdateAccount);
int statusCode = res.getStatus();
}
Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
- Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE);
+ Assert.assertEquals(statusCode, Response.Status.BAD_REQUEST.getStatusCode());
}
// ---------------------------------------------------------------
// Success outcomes
@Override
@Test(dataProvider = "testName", dataProviderClass = AbstractServiceTest.class,
- dependsOnMethods = {"testSubmitRequest", "updateNonExistent"})
+ dependsOnMethods = {"testSubmitRequest", "updateWrongUser"})
public void delete(String testName) throws Exception {
// Perform setup.
// Check the status code of the response: does it match
// the expected response(s)?
if (logger.isDebugEnabled()) {
- logger.debug("testSubmitRequest: url=" + url +
- " status=" + statusCode);
+ logger.debug("testSubmitRequest: url=" + url
+ + " status=" + statusCode);
}
Assert.assertEquals(statusCode, EXPECTED_STATUS);
// ---------------------------------------------------------------
// Utility methods used by tests above
// ---------------------------------------------------------------
- private AccountsCommon createAccountInstance(String firstName, String lastName, String screenName,
- String passwd, String email) {
+ /*
+ * createAccountInstance
+ * @param tenant fillup tenant
+ * @param user to fill up user
+ * @param password to fill up password
+ */
+ private AccountsCommon createAccountInstance(String screenName,
+ String passwd, String email, boolean tenant, boolean user, boolean password) {
AccountsCommon account = new AccountsCommon();
- account.setFirstName(firstName);
- account.setLastName(lastName);
account.setScreenName(screenName);
- account.setUserId(screenName);
- account.setPassword(Base64.encodeBase64(passwd.getBytes()));
+ if (user) {
+ account.setUserId(screenName);
+ }
+ if (password) {
+ account.setPassword(Base64.encodeBase64(passwd.getBytes()));
+ }
account.setEmail(email);
account.setPhone("1234567890");
+ if (tenant) {
+ List<AccountsCommon.Tenant> atl = new ArrayList<AccountsCommon.Tenant>();
+ AccountsCommon.Tenant at = new AccountsCommon.Tenant();
+ at.setId(UUID.randomUUID().toString());
+ at.setName("movingimages.us");
+ atl.add(at);
+
+ AccountsCommon.Tenant at2 = new AccountsCommon.Tenant();
+ at2.setId(UUID.randomUUID().toString());
+ at2.setName("collectionspace.org");
+ atl.add(at2);
+ account.setTenant(atl);
+ }
if (logger.isDebugEnabled()) {
logger.debug("to be created, account common");
logger.debug(objectAsXmlString(account,
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
-package org.collectionspace.services.client.test;
+package org.collectionspace.services.account.client.test;
import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
import java.util.UUID;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
+import javax.persistence.NoResultException;
import javax.persistence.Persistence;
import javax.persistence.Query;
import org.collectionspace.services.account.AccountsCommon;
+import org.collectionspace.services.account.AccountsCommon.Tenant;
import org.collectionspace.services.account.Status;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
}
}
+ @SuppressWarnings("unchecked")
+ @Test(dataProvider = "testName", dataProviderClass = AccountTest.class)
+ public void createTest(String testName) throws Exception {
+ AccountsCommon account = null;
+ try {
+ account = findAccount("test");
+ if (account != null) {
+ return;
+ }
+ } catch (NoResultException nre) {
+ //ignore
+ }
+ if (account == null) {
+ account = new AccountsCommon();
+ }
+ account.setScreenName("test");
+ account.setEmail("test.test@berkeley.edu");
+ account.setUserId("test");
+ account.setStatus(Status.ACTIVE);
+ id = UUID.randomUUID().toString();
+ account.setCsid(id);
+
+ Tenant tenant = new Tenant();
+ tenant.setId("1");
+ tenant.setName("movingimages.us");
+ List<Tenant> lt = new ArrayList<Tenant>();
+ lt.add(tenant);
+ account.setTenant(lt);
+ em.getTransaction().begin();
+ em.persist(account);
+ // Commit the transaction
+ em.getTransaction().commit();
+ if (logger.isDebugEnabled()) {
+ logger.debug("created/updated account "
+ + " screen name=" + account.getScreenName()
+ + " email=" + account.getEmail());
+ }
+ }
+
@SuppressWarnings("unchecked")
@Test(dataProvider = "testName", dataProviderClass = AccountTest.class)
public void create(String testName) throws Exception {
AccountsCommon account = new AccountsCommon();
account.setScreenName("john");
- account.setFirstName("John");
- account.setLastName("Doe");
account.setEmail("john.doe@berkeley.edu");
account.setUserId("johndoe");
account.setStatus(Status.ACTIVE);
id = UUID.randomUUID().toString();
account.setCsid(id);
- account.setTenantid("123"); //set by service runtime
+ Tenant tenant = new Tenant();
+ tenant.setId("123");
+ tenant.setName("movingimages.us.standalone");
+ List<Tenant> lt = new ArrayList<Tenant>();
+ lt.add(tenant);
+ account.setTenant(lt);
em.getTransaction().begin();
em.persist(account);
// Commit the transaction
em.getTransaction().commit();
if (logger.isDebugEnabled()) {
- logger.debug("created account " +
- " first name=" + account.getFirstName() +
- " email=" + account.getEmail());
+ logger.debug("created account "
+ + " screen name=" + account.getScreenName()
+ + " email=" + account.getEmail());
}
}
AccountsCommon account = findAccount("john");
Assert.assertNotNull(account);
if (logger.isDebugEnabled()) {
- logger.debug("read account " +
- " first name=" + account.getFirstName());
+ logger.debug("read account "
+ + " screen name=" + account.getScreenName());
}
}
Assert.assertEquals(no, 1);
AccountsCommon account = findAccount("john");
if (logger.isDebugEnabled()) {
- logger.debug("updated account " +
- " first name=" + account.getFirstName() +
- " email=" + account.getEmail());
+ logger.debug("updated account "
+ + " screen name=" + account.getScreenName()
+ + " email=" + account.getEmail());
}
}
@Test(dataProvider = "testName", dataProviderClass = AccountTest.class,
dependsOnMethods = {"update"})
public void delete(String testName) throws Exception {
- Query q = em.createQuery("delete from org.collectionspace.services.account.AccountsCommon where csid=:csid");
- q.setParameter("csid", id);
// Begin transaction
em.getTransaction().begin();
- int no = q.executeUpdate();
- ;
+ AccountsCommon account = findAccount("john");
+ em.remove(account);
if (logger.isDebugEnabled()) {
- logger.debug("deleting account " +
- " csid=" + id);
+ logger.debug("deleting account "
+ + " csid=" + id);
}
// Commit the transaction
em.getTransaction().commit();
- Assert.assertEquals(no, 1);
if (logger.isDebugEnabled()) {
- logger.debug("deleted account " +
- " csid=" + id);
+ logger.debug("deleted account "
+ + " csid=" + id);
}
}
http://java.sun.com/xml/ns/persistence/orm http://java.sun.com/xml/ns/persistence/orm_1_0.xsd" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:orm="http://java.sun.com/xml/ns/persistence/orm" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<persistence-unit name="org.collectionspace.services.account">
<class>org.collectionspace.services.account.AccountsCommon</class>
+ <class>org.collectionspace.services.account.AccountsCommon$Tenant</class>
<class>org.collectionspace.services.account.AccountsCommonList</class>
<class>org.collectionspace.services.account.AccountsCommonList$AccountListItem</class>
<properties>
log4j.logger.httpclient=INFO\r
log4j.logger.org.jboss.resteasy=INFO\r
log4j.logger.org.hibernate=INFO\r
+log4j.logger.org.hibernate.cfg=WARN\r
<!--
Account schema (XSD)
-
+
Entity : Account
Part : Common
Used for: JAXB binding between XML and Java objects
-
+
$LastChangedRevision: 916 $
$LastChangedDate: 2009-11-05 16:59:20 -0800 (Thu, 05 Nov 2009) $
-->
<xs:schema
- xmlns:xs="http://www.w3.org/2001/XMLSchema"
- xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
- xmlns:hj="http://hyperjaxb3.jvnet.org/ejb/schemas/customizations"
- xmlns:orm="http://java.sun.com/xml/ns/persistence/orm"
- xmlns:ns="http://collectionspace.org/servics/account"
- xmlns="http://collectionspace.org/services/account"
- targetNamespace="http://collectionspace.org/services/account"
- version="0.1"
- jaxb:extensionBindingPrefixes="hj orm"
->
+ xmlns:xs="http://www.w3.org/2001/XMLSchema"
+ xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
+ xmlns:hj="http://hyperjaxb3.jvnet.org/ejb/schemas/customizations"
+ xmlns:orm="http://java.sun.com/xml/ns/persistence/orm"
+ xmlns:ns="http://collectionspace.org/servics/account"
+ xmlns="http://collectionspace.org/services/account"
+ targetNamespace="http://collectionspace.org/services/account"
+ version="0.1"
+ jaxb:extensionBindingPrefixes="hj orm"
+ >
-<!--
+ <!--
Avoid XmlRootElement nightmare:
See http://weblogs.java.net/blog/kohsuke/archive/2006/03/why_does_jaxb_p.html
-->
</xs:appinfo>
</xs:annotation>
</xs:element>
- <xs:element name="firstName" type="xs:string" minOccurs="1" maxOccurs="1">
- <xs:annotation>
- <xs:appinfo>
- <hj:basic>
- <orm:column name="first_name" length="256" nullable="false"/>
- </hj:basic>
- </xs:appinfo>
- </xs:annotation>
- </xs:element>
- <xs:element name="lastName" type="xs:string" minOccurs="1" maxOccurs="1">
- <xs:annotation>
- <xs:appinfo>
- <hj:basic>
- <orm:column name="last_name" length="256" nullable="false"/>
- </hj:basic>
- </xs:appinfo>
- </xs:annotation>
- </xs:element>
- <xs:element name="mi" type="xs:string">
- <xs:annotation>
- <xs:appinfo>
- <hj:basic>
- <orm:column name="mi" length="1" nullable="true"/>
- </hj:basic>
- </xs:appinfo>
- </xs:annotation>
- </xs:element>
<xs:element name="email" type="xs:string" minOccurs="1" maxOccurs="1">
<xs:annotation>
<xs:appinfo>
</xs:annotation>
</xs:element>
<!-- userid, could be calnet id, openid URI -->
- <xs:element name="userId" type="xs:string" minOccurs="0" maxOccurs="1">
+ <xs:element name="userId" type="xs:string" minOccurs="1" maxOccurs="1">
<xs:annotation>
<xs:appinfo>
<hj:basic>
</xs:appinfo>
</xs:annotation>
</xs:element>
- <!-- tenant id is not needed from service consumer, it will be ignored if provided -->
- <!-- tenant id is for internal use for CollectionSpace -->
- <!-- it is assumed that account creation is performed under valid -->
- <!-- tenant context. tenant id is never returned in response -->
- <xs:element name="tenantid" type="xs:string" minOccurs="0" maxOccurs="1">
- <xs:annotation>
- <xs:appinfo>
- <hj:basic>
- <orm:column name="tenantid" nullable="false"/>
- </hj:basic>
- </xs:appinfo>
- </xs:annotation>
+ <xs:element name="tenant" minOccurs="1" maxOccurs="unbounded">
+ <xs:complexType>
+ <xs:annotation>
+ <xs:appinfo>
+ <hj:entity>
+ <orm:table name="tenants"/>
+ </hj:entity>
+ </xs:appinfo>
+ </xs:annotation>
+ <xs:sequence>
+ <xs:element name="id" type="xs:string" minOccurs="1">
+ <xs:annotation>
+ <xs:appinfo>
+ <hj:basic>
+ <orm:column name="id" nullable="false"/>
+ </hj:basic>
+ </xs:appinfo>
+ </xs:annotation>
+ </xs:element>
+ <xs:element name="name" type="xs:string" minOccurs="1">
+ <xs:annotation>
+ <xs:appinfo>
+ <hj:basic>
+ <orm:column name="name" nullable="false"/>
+ </hj:basic>
+ </xs:appinfo>
+ </xs:annotation>
+ </xs:element>
+ </xs:sequence>
+
+ </xs:complexType>
</xs:element>
<xs:element name="status" type="status">
<xs:annotation>
<groupId>org.collectionspace.services</groupId>\r
<version>1.0</version>\r
</parent>\r
- \r
+\r
<modelVersion>4.0.0</modelVersion>\r
<groupId>org.collectionspace.services</groupId>\r
<artifactId>org.collectionspace.services.account.service</artifactId>\r
<groupId>org.slf4j</groupId>\r
<artifactId>slf4j-log4j12</artifactId>\r
</dependency>\r
- \r
+\r
<dependency>\r
<groupId>junit</groupId>\r
<artifactId>junit</artifactId>\r
<artifactId>testng</artifactId>\r
<version>5.6</version>\r
</dependency>\r
- \r
+\r
<!-- apache -->\r
<dependency>\r
<groupId>commons-beanutils</groupId>\r
<artifactId>commons-logging</artifactId>\r
<version>1.1</version>\r
</dependency>\r
- <!-- javax -->\r
+ <!-- javax -->\r
\r
\r
<dependency>\r
<scope>provided</scope>\r
</dependency>\r
\r
- \r
+\r
<!-- jboss -->\r
\r
<dependency>\r
<artifactId>resteasy-multipart-provider</artifactId>\r
<version>1.1.GA</version>\r
</dependency>\r
- \r
+\r
\r
</dependencies>\r
- \r
+\r
<build>\r
<finalName>collectionspace-services-account</finalName>\r
<plugins>\r
path.path("" + csid);
Response response = Response.created(path.build()).build();
return response;
+ } catch (BadRequestException bre) {
+ Response response = Response.status(
+ Response.Status.BAD_REQUEST).entity("Create failed reason " + bre.getErrorReason()).type("text/plain").build();
+ throw new WebApplicationException(response);
} catch (UnauthorizedException ue) {
Response response = Response.status(
Response.Status.UNAUTHORIZED).entity("Create failed reason " + ue.getErrorReason()).type("text/plain").build();
import org.collectionspace.services.account.AccountsCommonList.AccountListItem;
import org.collectionspace.services.account.Status;
import org.collectionspace.services.common.document.AbstractDocumentHandler;
+import org.collectionspace.services.common.document.BadRequestException;
import org.collectionspace.services.common.document.DocumentWrapper;
-import org.collectionspace.services.nuxeo.util.NuxeoUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
/**
*
public class AccountDocumentHandler
extends AbstractDocumentHandler<AccountsCommon, AccountsCommonList, AccountsCommon, List> {
+ private final Logger logger = LoggerFactory.getLogger(AccountDocumentHandler.class);
private AccountsCommon account;
private AccountsCommonList accountList;
public void handleCreate(DocumentWrapper<AccountsCommon> wrapDoc) throws Exception {
String id = UUID.randomUUID().toString();
AccountsCommon account = wrapDoc.getWrappedObject();
+ if (account.getUserId() == null || "".equals(account.getUserId())) {
+ String msg = "userId is missing";
+ logger.error(msg);
+ throw new BadRequestException(msg);
+ }
+ List<AccountsCommon.Tenant> tl = account.getTenant();
+ if (tl == null || tl.size() == 0) {
+ String msg = "missing tenant information!";
+ logger.error(msg);
+ throw new BadRequestException(msg);
+ }
account.setCsid(id);
account.setStatus(Status.ACTIVE);
}
@Override
public void handleUpdate(DocumentWrapper<AccountsCommon> wrapDoc) throws Exception {
+ if (account.getPassword() != null
+ && (account.getUserId() == null || "".equals(account.getUserId()))) {
+ String msg = "userId is missing";
+ logger.error(msg);
+ throw new BadRequestException(msg);
+ }
}
@Override
AccountListItem accListItem = new AccountListItem();
accListItem.setScreenName(account.getScreenName());
accListItem.setEmail(account.getEmail());
- accListItem.setFirstName(account.getFirstName());
- accListItem.setLastName(account.getLastName());
accListItem.setStatus(account.getStatus());
String id = account.getCsid();
accListItem.setUri(getServiceContextPath() + id);
* @param account
*/
private void sanitize(AccountsCommon account) {
- account.setTenantid("");
account.setPassword(null);
}
}
*/
package org.collectionspace.services.account.storage;
+import java.util.ArrayList;
+import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
-import javax.persistence.NoResultException;
import javax.persistence.Query;
import org.apache.commons.codec.binary.Base64;
import org.collectionspace.services.account.AccountsCommon;
import org.collectionspace.services.common.context.ServiceContext;
import org.collectionspace.services.common.document.BadRequestException;
import org.collectionspace.services.common.document.DocumentException;
-import org.collectionspace.services.common.document.DocumentFilter;
import org.collectionspace.services.common.document.DocumentHandler;
import org.collectionspace.services.common.document.DocumentHandler.Action;
import org.collectionspace.services.common.document.DocumentNotFoundException;
import org.collectionspace.services.common.document.DocumentWrapperImpl;
import org.collectionspace.services.common.security.SecurityUtils;
import org.collectionspace.services.common.storage.jpa.JpaStorageClient;
+
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
em.getTransaction().begin();
//if userid and password are given, add to default id provider
if (account.getUserId() != null && account.getPassword() != null) {
- User user = createUser(account, ctx.getTenantId());
+ User user = createUser(account);
em.persist(user);
}
- account.setTenantid(ctx.getTenantId());
+// if (account.getTenant() != null) {
+// UserTenant ut = createTenantAssoc(account);
+// em.persist(ut);
+// }
em.persist(account);
em.getTransaction().commit();
handler.complete(Action.CREATE, wrapDoc);
return (String) getValue(account, "getCsid");
+ } catch (BadRequestException bre) {
+ if (em != null && em.getTransaction().isActive()) {
+ em.getTransaction().rollback();
+ }
+ throw bre;
} catch (Exception e) {
if (em != null && em.getTransaction().isActive()) {
em.getTransaction().rollback();
if (account.getUserId() != null && account.getPassword() != null) {
User userFound = getUser(em, account);
- User user = createUser(account, ctx.getTenantId());
+ User user = createUser(account);
em.merge(user);
}
em.merge(account);
em.getTransaction().commit();
handler.complete(Action.UPDATE, wrapDoc);
} catch (BadRequestException bre) {
+ if (em != null && em.getTransaction().isActive()) {
+ em.getTransaction().rollback();
+ }
throw bre;
} catch (DocumentException de) {
+ if (em != null && em.getTransaction().isActive()) {
+ em.getTransaction().rollback();
+ }
throw de;
} catch (Exception e) {
if (logger.isDebugEnabled()) {
//if userid gives any indication about the id provider, it should
//be used to avoid the following approach
- User userLocal = em.find(User.class, accountFound.getUserId());
Query usrDel = null;
+ User userLocal = getUser(em, accountFound);
if (userLocal != null) {
StringBuilder usrDelStr = new StringBuilder("DELETE FROM ");
usrDelStr.append(User.class.getCanonicalName());
usrDel.setParameter("username", accountFound.getUserId());
}
em.getTransaction().begin();
- int accDelCount = accDel.executeUpdate();
- if (accDelCount != 1) {
- if (em != null && em.getTransaction().isActive()) {
- em.getTransaction().rollback();
- }
- }
+// int accDelCount = accDel.executeUpdate();
+// if (accDelCount != 1) {
+// if (em != null && em.getTransaction().isActive()) {
+// em.getTransaction().rollback();
+// }
+// }
if (userLocal != null) {
int usrDelCount = usrDel.executeUpdate();
if (usrDelCount != 1) {
throw new DocumentNotFoundException(msg);
}
}
+ em.remove(accountFound);
em.getTransaction().commit();
} catch (DocumentException de) {
+ if (em != null && em.getTransaction().isActive()) {
+ em.getTransaction().rollback();
+ }
throw de;
} catch (Exception e) {
if (logger.isDebugEnabled()) {
return true;
}
- private User createUser(AccountsCommon account, String tenantId) {
+ private User createUser(AccountsCommon account) {
User user = new User();
- user.setTenantid(tenantId);
user.setUsername(account.getUserId());
byte[] bpass = Base64.decodeBase64(account.getPassword());
SecurityUtils.validatePassword(new String(bpass));
}
return userFound;
}
+
+// private UserTenant createTenantAssoc(AccountsCommon account) {
+// UserTenant userTenant = new UserTenant();
+// userTenant.setUserId(account.getUserId());
+// List<AccountsCommon.Tenant> atl = account.getTenant();
+// List<UserTenant.Tenant> utl =
+// new ArrayList<UserTenant.Tenant>();
+// for (AccountsCommon.Tenant at : atl) {
+// UserTenant.Tenant ut = new UserTenant.Tenant();
+// ut.setId(at.getId());
+// ut.setName(at.getName());
+// utl.add(ut);
+// }
+// userTenant.setTenant(utl);
+// return userTenant;
+// }
}
<?xml version="1.0" encoding="UTF-8"?>\r
<project xmlns="http://maven.apache.org/POM/4.0.0"\r
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"\r
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">\r
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"\r
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">\r
\r
<parent>\r
<artifactId>org.collectionspace.services.authentication</artifactId>\r
<artifactId>org.collectionspace.services.client</artifactId>\r
<version>1.0</version>\r
</dependency>\r
- <!-- authentication tests use CollectionObject service -->\r
+ <!-- authentication tests use CollectionObject service and Account service -->\r
+ <dependency>\r
+ <groupId>org.collectionspace.services</groupId>\r
+ <artifactId>org.collectionspace.services.account.client</artifactId>\r
+ <version>1.0</version>\r
+ </dependency>\r
<dependency>\r
<groupId>org.collectionspace.services</groupId>\r
<artifactId>org.collectionspace.services.collectionobject.client</artifactId>\r
<artifactId>mysql-connector-java</artifactId>\r
</dependency>\r
</dependencies>\r
- \r
+\r
<build>\r
<finalName>cspace-services-collectionobject-client</finalName>\r
<plugins>\r
drop table if exists roles;
drop table if exists users;
drop table if exists users_roles;
-create table roles (rolename varchar(255) not null, rolegroup varchar(255) not null, tenantid varchar(255) not null, primary key (rolename));
-create table users (username varchar(255) not null, passwd varchar(128) not null, tenantid varchar(255) not null, primary key (username));
-create table users_roles (HJID bigint not null auto_increment, rolename varchar(255) not null, tenantid varchar(255) not null, username varchar(255) not null, primary key (HJID));
+create table roles (rolename varchar(255) not null, rolegroup varchar(255) not null, primary key (rolename));
+create table users (username varchar(255) not null, passwd varchar(128) not null, primary key (username));
+create table users_roles (HJID bigint not null auto_increment, rolename varchar(255) not null, username varchar(255) not null, primary key (HJID));
--\r
use cspace;\r
\r
-INSERT INTO `users` (`username`,`passwd`, `tenantid`) VALUES ('test','n4bQgYhMfWWaL+qgxVrQFaO/TxsrC4Is0V1sFbDwCgg=', '1');\r
+insert into `users` (`username`,`passwd`) VALUES ('test','n4bQgYhMfWWaL+qgxVrQFaO/TxsrC4Is0V1sFbDwCgg=');\r
\r
-insert into roles (rolename, rolegroup, `tenantid`) values ('collections_manager', 'collections', '1');\r
-insert into roles (rolename, rolegroup, `tenantid`) values ('collections_registrar', 'collections', '1');\r
+insert into `roles` (`rolename`, `rolegroup`) values ('kernel', 'kernel');\r
+insert into `roles` (`rolename`, `rolegroup`) values ('collections_manager', 'collections');\r
+insert into `roles` (`rolename`, `rolegroup`) values ('collections_registrar', 'collections');\r
\r
-insert into users_roles(username, rolename, `tenantid`) values ('test', 'collections_manager', '1');\r
-insert into users_roles(username, rolename, `tenantid`) values('admin', 'collections_registrar', '1');
\ No newline at end of file
+insert into `users_roles`(`username`, `rolename`) values ('test', 'collections_manager');\r
+insert into `users_roles`(`username`, `rolename`) values('admin', 'collections_registrar');
\ No newline at end of file
*/
package org.collectionspace.services.authentication.client;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
+import org.apache.commons.codec.binary.Base64;
+import org.collectionspace.services.client.AccountClient;
+import org.collectionspace.services.account.AccountsCommon;
import org.jboss.resteasy.client.ClientResponse;
import org.testng.Assert;
import org.testng.annotations.Test;
/** The known resource id. */
private String knownResourceId = null;
+ private String barneyAccountId = null;
+ private String babybopAccountId = null;
/** The logger. */
final Logger logger = LoggerFactory.getLogger(AuthenticationServiceTest.class);
return null;
}
+ @Test(dataProvider = "testName", dataProviderClass = AbstractServiceTest.class)
+ public void createAccounts(String testName) throws Exception {
+ // Perform setup, such as initializing the type of service request
+ // (e.g. CREATE, DELETE), its valid and expected status codes, and
+ // its associated HTTP method name (e.g. POST, DELETE).
+ setupCreate(testName);
+ AccountClient accountClient = new AccountClient();
+ if (!accountClient.isServerSecure()) {
+ logger.warn("set -Dcspace.server.secure=true to run security tests");
+ return;
+ }
+ accountClient.setProperty(CollectionSpaceClient.AUTH_PROPERTY,
+ "true");
+ accountClient.setProperty(CollectionSpaceClient.USER_PROPERTY,
+ "test");
+ accountClient.setProperty(
+ CollectionSpaceClient.PASSWORD_PROPERTY, "test");
+ // Submit the request to the service and store the response.
+ AccountsCommon account =
+ createAccountInstance("barney", "barney08", "barney@dinoland.com", "1");
+ ClientResponse<Response> res = accountClient.create(account);
+ int statusCode = res.getStatus();
+
+ if (logger.isDebugEnabled()) {
+ logger.debug(testName + ": barney status = " + statusCode);
+ }
+ Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
+ invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
+ // Store the ID returned from this create operation
+ // for additional tests below.
+ barneyAccountId = extractId(res);
+ if (logger.isDebugEnabled()) {
+ logger.debug(testName + ": barneyAccountId=" + barneyAccountId);
+ }
+
+ account = createAccountInstance("babybop", "babybop09", "babybop@dinoland.com", "non-existent");
+ res = accountClient.create(account);
+ statusCode = res.getStatus();
+
+ if (logger.isDebugEnabled()) {
+ logger.debug(testName + ": babybop status = " + statusCode);
+ }
+ Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
+ invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
+
+ // Store the ID returned from this create operation
+ // for additional tests below.
+ babybopAccountId = extractId(res);
+ if (logger.isDebugEnabled()) {
+ logger.debug(testName + ": babybopAccountId=" + babybopAccountId);
+ }
+
+ }
+
+
/* (non-Javadoc)
* @see org.collectionspace.services.client.test.AbstractServiceTest#create()
*/
- @Test(dataProvider = "testName", dataProviderClass = AbstractServiceTest.class)
+ @Test(dataProvider = "testName", dataProviderClass = AbstractServiceTest.class,
+ dependsOnMethods = {"createAccounts"})
@Override
public void create(String testName) {
+ setupCreate(testName);
CollectionObjectClient collectionObjectClient = new CollectionObjectClient();
String identifier = this.createIdentifier();
MultipartOutput multipart = createCollectionObjectInstance(
collectionObjectClient.setProperty(CollectionSpaceClient.AUTH_PROPERTY,
"true");
collectionObjectClient.setProperty(CollectionSpaceClient.USER_PROPERTY,
- "test");
+ "barney");
collectionObjectClient.setProperty(
- CollectionSpaceClient.PASSWORD_PROPERTY, "test");
+ CollectionSpaceClient.PASSWORD_PROPERTY, "barney08");
try {
collectionObjectClient.setupHttpClient();
collectionObjectClient.setProxy();
}
/**
- * Creates the collection object instance without user.
+ * Creates the collection object instance without password.
*/
- @Test(dependsOnMethods = {"create"})
- public void createWithoutUser() {
+ @Test(dependsOnMethods = {"createAccounts"})
+ public void createWithoutPassword() {
+ banner("createWithoutPassword");
CollectionObjectClient collectionObjectClient = new CollectionObjectClient();
String identifier = this.createIdentifier();
MultipartOutput multipart = createCollectionObjectInstance(
}
collectionObjectClient.setProperty(CollectionSpaceClient.AUTH_PROPERTY,
"true");
- collectionObjectClient.removeProperty(CollectionSpaceClient.USER_PROPERTY);
- collectionObjectClient.setProperty(
- CollectionSpaceClient.PASSWORD_PROPERTY, "test");
+ collectionObjectClient.setProperty(CollectionSpaceClient.USER_PROPERTY,
+ "test");
+ collectionObjectClient.removeProperty(CollectionSpaceClient.PASSWORD_PROPERTY);
try {
collectionObjectClient.setupHttpClient();
collectionObjectClient.setProxy();
} catch (Exception e) {
- logger.error("createWithoutUser: caught " + e.getMessage());
+ logger.error("createWithoutPassword: caught " + e.getMessage());
return;
}
ClientResponse<Response> res = collectionObjectClient.create(multipart);
if (logger.isDebugEnabled()) {
- logger.debug("createWithoutUser: status = " + res.getStatus());
+ logger.debug("createWithoutPassword: status = " + res.getStatus());
}
Assert.assertEquals(res.getStatus(), Response.Status.UNAUTHORIZED.getStatusCode(), "expected " + Response.Status.UNAUTHORIZED.getStatusCode());
}
/**
- * Creates the collection object instance without password.
+ * Creates the collection object with unknown user
*/
- @Test(dependsOnMethods = {"createWithoutUser"})
- public void createWithoutPassword() {
+ @Test(dependsOnMethods = {"createAccounts"})
+ public void createWithUnknownUser() {
+ banner("createWithUnknownUser");
CollectionObjectClient collectionObjectClient = new CollectionObjectClient();
String identifier = this.createIdentifier();
MultipartOutput multipart = createCollectionObjectInstance(
collectionObjectClient.setProperty(CollectionSpaceClient.AUTH_PROPERTY,
"true");
collectionObjectClient.setProperty(CollectionSpaceClient.USER_PROPERTY,
- "test");
- collectionObjectClient.removeProperty(CollectionSpaceClient.PASSWORD_PROPERTY);
+ "foo");
+ collectionObjectClient.setProperty(CollectionSpaceClient.PASSWORD_PROPERTY,
+ "bar");
try {
collectionObjectClient.setupHttpClient();
collectionObjectClient.setProxy();
} catch (Exception e) {
- logger.error("createWithoutPassword: caught " + e.getMessage());
+ logger.error("createWithUnknownUser: caught " + e.getMessage());
return;
}
ClientResponse<Response> res = collectionObjectClient.create(multipart);
if (logger.isDebugEnabled()) {
- logger.debug("createWithoutPassword: status = " + res.getStatus());
+ logger.debug("createWithUnknownUser: status = " + res.getStatus());
}
Assert.assertEquals(res.getStatus(), Response.Status.UNAUTHORIZED.getStatusCode(), "expected " + Response.Status.UNAUTHORIZED.getStatusCode());
}
/**
* Creates the collection object instance with incorrect password.
*/
- @Test(dependsOnMethods = {"createWithoutPassword"})
+ @Test(dependsOnMethods = {"createAccounts"})
public void createWithIncorrectPassword() {
+ banner("createWithIncorrectPassword");
CollectionObjectClient collectionObjectClient = new CollectionObjectClient();
String identifier = this.createIdentifier();
MultipartOutput multipart = createCollectionObjectInstance(
}
/**
- * Creates the collection object instance without user password.
+ * Creates the collection object instance with incorrect user password.
*/
- @Test(dependsOnMethods = {"createWithoutPassword"})
- public void createWithoutUserPassword() {
+ @Test(dependsOnMethods = {"createAccounts"})
+ public void createWithIncorrectUserPassword() {
+ banner("createWithIncorrectUserPassword");
CollectionObjectClient collectionObjectClient = new CollectionObjectClient();
String identifier = this.createIdentifier();
MultipartOutput multipart = createCollectionObjectInstance(
}
collectionObjectClient.setProperty(CollectionSpaceClient.AUTH_PROPERTY,
"true");
- collectionObjectClient.removeProperty(CollectionSpaceClient.USER_PROPERTY);
- collectionObjectClient.removeProperty(CollectionSpaceClient.PASSWORD_PROPERTY);
+ collectionObjectClient.setProperty(CollectionSpaceClient.USER_PROPERTY,
+ "foo");
+ collectionObjectClient.setProperty(
+ CollectionSpaceClient.PASSWORD_PROPERTY, "bar");
try {
collectionObjectClient.setupHttpClient();
collectionObjectClient.setProxy();
} catch (Exception e) {
- logger.error("createWithoutUserPassword: caught " + e.getMessage());
+ logger.error("createWithIncorrectUserPassword: caught " + e.getMessage());
return;
}
ClientResponse<Response> res = collectionObjectClient.create(multipart);
if (logger.isDebugEnabled()) {
- logger.debug("createWithoutUserPassword: status = " + res.getStatus());
+ logger.debug("createWithIncorrectUserPassword: status = "
+ + res.getStatus());
}
- Assert.assertEquals(res.getStatus(), Response.Status.FORBIDDEN.getStatusCode(), "expected " + Response.Status.FORBIDDEN.getStatusCode());
+ Assert.assertEquals(res.getStatus(), Response.Status.UNAUTHORIZED.getStatusCode(), "expected " + Response.Status.UNAUTHORIZED.getStatusCode());
}
/**
* Creates the collection object instance with incorrect user password.
*/
- @Test(dependsOnMethods = {"createWithoutPassword"})
- public void createWithIncorrectUserPassword() {
+ @Test(dependsOnMethods = {"createAccounts"})
+ public void createWithoutTenant() {
+ banner("createWithoutTenant");
CollectionObjectClient collectionObjectClient = new CollectionObjectClient();
String identifier = this.createIdentifier();
MultipartOutput multipart = createCollectionObjectInstance(
collectionObjectClient.setProperty(CollectionSpaceClient.AUTH_PROPERTY,
"true");
collectionObjectClient.setProperty(CollectionSpaceClient.USER_PROPERTY,
- "foo");
+ "babybop");
collectionObjectClient.setProperty(
- CollectionSpaceClient.PASSWORD_PROPERTY, "bar");
+ CollectionSpaceClient.PASSWORD_PROPERTY, "babybop09");
try {
collectionObjectClient.setupHttpClient();
collectionObjectClient.setProxy();
} catch (Exception e) {
- logger.error("createWithIncorrectUserPassword: caught " + e.getMessage());
+ logger.error("createWithoutTenant: caught " + e.getMessage());
return;
}
ClientResponse<Response> res = collectionObjectClient.create(multipart);
if (logger.isDebugEnabled()) {
- logger.debug("createWithIncorrectUserPassword: status = " +
- res.getStatus());
+ logger.debug("createWithoutTenant: status = "
+ + res.getStatus());
}
Assert.assertEquals(res.getStatus(), Response.Status.UNAUTHORIZED.getStatusCode(), "expected " + Response.Status.UNAUTHORIZED.getStatusCode());
}
*/
@Override
@Test(dataProvider = "testName", dataProviderClass = AbstractServiceTest.class,
- dependsOnMethods = {"createWithIncorrectUserPassword"})
+ dependsOnMethods = {"create"})
public void delete(String testName) {
+ setupDelete(testName);
CollectionObjectClient collectionObjectClient = new CollectionObjectClient();
collectionObjectClient = new CollectionObjectClient();
if (!collectionObjectClient.isServerSecure()) {
Response.Status.OK.getStatusCode(), "expected " + Response.Status.OK.getStatusCode());
}
+ @Test(dataProvider = "testName", dataProviderClass = AbstractServiceTest.class,
+ dependsOnMethods = {"delete"})
+ public void deleteAccounts(String testName) throws Exception {
+
+ // Perform setup.
+ setupDelete(testName);
+ AccountClient accountClient = new AccountClient();
+ if (!accountClient.isServerSecure()) {
+ logger.warn("set -Dcspace.server.secure=true to run security tests");
+ return;
+ }
+ accountClient.setProperty(CollectionSpaceClient.AUTH_PROPERTY,
+ "true");
+ accountClient.setProperty(CollectionSpaceClient.USER_PROPERTY,
+ "test");
+ accountClient.setProperty(
+ CollectionSpaceClient.PASSWORD_PROPERTY, "test");
+ // Submit the request to the service and store the response.
+ ClientResponse<Response> res = accountClient.delete(barneyAccountId);
+ int statusCode = res.getStatus();
+ if (logger.isDebugEnabled()) {
+ logger.debug(testName + ": barney status = " + statusCode);
+ }
+ Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
+ invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
+
+ res = accountClient.delete(babybopAccountId);
+ statusCode = res.getStatus();
+ if (logger.isDebugEnabled()) {
+ logger.debug(testName + ": babybop status = " + statusCode);
+ }
+ Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
+ invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
+ }
+
// ---------------------------------------------------------------
// Utility methods used by tests above
// ---------------------------------------------------------------
return multipart;
}
+ private AccountsCommon createAccountInstance(String screenName,
+ String passwd, String email, String tenantId) {
+
+ AccountsCommon account = new AccountsCommon();
+ account.setScreenName(screenName);
+ account.setUserId(screenName);
+ account.setPassword(Base64.encodeBase64(passwd.getBytes()));
+ account.setEmail(email);
+ account.setPhone("1234567890");
+ List<AccountsCommon.Tenant> atl = new ArrayList<AccountsCommon.Tenant>();
+
+ AccountsCommon.Tenant at = new AccountsCommon.Tenant();
+ at.setId(tenantId);//for testing purposes
+ at.setName("movingimages.us");
+ atl.add(at);
+ //disable 2nd tenant till tenant identification is in effect
+ //on the service side for 1-n user-tenants
+// AccountsCommon.Tenant at2 = new AccountsCommon.Tenant();
+// at2.setId(UUID.randomUUID().toString());
+// at2.setName("collectionspace.org");
+// atl.add(at2);
+ account.setTenant(atl);
+
+ if (logger.isDebugEnabled()) {
+ logger.debug("to be created, account common");
+ logger.debug(objectAsXmlString(account,
+ AccountsCommon.class));
+ }
+ return account;
+
+ }
+
/* (non-Javadoc)
* @see org.collectionspace.services.client.test.AbstractServiceTest#createList()
*/
<artifactId>testng</artifactId>
<version>5.6</version>
</dependency>
- <dependency>
- <groupId>org.collectionspace.services</groupId>
- <artifactId>org.collectionspace.services.client</artifactId>
- <version>1.0</version>
- </dependency>
</dependencies>
<build>
</xs:appinfo>
</xs:annotation>
<xs:sequence>
- <!-- tenant id is not needed from service consumer, it will be ignored if provided -->
- <!-- tenant id is for internal use for CollectionSpace -->
- <!-- it is assumed that account creation is performed under valid -->
- <!-- tenant context. tenant id is never returned in response -->
- <xs:element name="tenantid" type="xs:string" minOccurs="0" maxOccurs="1">
- <xs:annotation>
- <xs:appinfo>
- <hj:basic>
- <orm:column name="tenantid" nullable="false"/>
- </hj:basic>
- </xs:appinfo>
- </xs:annotation>
- </xs:element>
<xs:element name="username" type="xs:string" minOccurs="1" maxOccurs="1">
<xs:annotation>
<xs:appinfo>
</xs:appinfo>
</xs:annotation>
<xs:sequence>
- <!-- tenant id is not needed from service consumer, it will be ignored if provided -->
- <!-- tenant id is for internal use for CollectionSpace -->
- <!-- it is assumed that account creation is performed under valid -->
- <!-- tenant context. tenant id is never returned in response -->
- <xs:element name="tenantid" type="xs:string" minOccurs="0" maxOccurs="1">
- <xs:annotation>
- <xs:appinfo>
- <hj:basic>
- <orm:column name="tenantid" nullable="false"/>
- </hj:basic>
- </xs:appinfo>
- </xs:annotation>
- </xs:element>
<xs:element name="rolename" type="xs:string" minOccurs="1" maxOccurs="1">
<xs:annotation>
<xs:appinfo>
</xs:appinfo>
</xs:annotation>
<xs:sequence>
- <!-- tenant id is not needed from service consumer, it will be ignored if provided -->
- <!-- tenant id is for internal use for CollectionSpace -->
- <!-- it is assumed that account creation is performed under valid -->
- <!-- tenant context. tenant id is never returned in response -->
- <xs:element name="tenantid" type="xs:string" minOccurs="0" maxOccurs="1">
- <xs:annotation>
- <xs:appinfo>
- <hj:basic>
- <orm:column name="tenantid" nullable="false"/>
- </hj:basic>
- </xs:appinfo>
- </xs:annotation>
- </xs:element>
<xs:element name="username" type="xs:string" minOccurs="1" maxOccurs="1">
<xs:annotation>
<xs:appinfo>
</properties>
<dependencies>
+ <!-- slf4j not available due to classloading issues perhaps -->
<dependency>
- <groupId>org.slf4j</groupId>
- <artifactId>slf4j-api</artifactId>
- </dependency>
- <dependency>
- <groupId>org.slf4j</groupId>
- <artifactId>slf4j-log4j12</artifactId>
+ <groupId>commons-logging</groupId>
+ <artifactId>commons-logging</artifactId>
+ <version>1.1.1</version>
</dependency>
+
<!-- utilities -->
<dependency>
<groupId>junit</groupId>
<scope>test</scope>
</dependency>
-
-
- <!-- javax -->
+ <!-- javax -->
<dependency>
<groupId>javax.security</groupId>
<artifactId>jaas</artifactId>
*/\r
package org.collectionspace.authentication;\r
\r
-import java.lang.reflect.Constructor;\r
-import java.security.Principal;\r
import java.security.acl.Group;\r
-import java.sql.Connection;\r
-import java.sql.PreparedStatement;\r
-import java.sql.ResultSet;\r
-import java.sql.SQLException;\r
+import java.util.ArrayList;\r
+import java.util.Collection;\r
+import java.util.List;\r
\r
-import java.util.HashMap;\r
import java.util.Map;\r
-import javax.naming.InitialContext;\r
-import javax.naming.NamingException;\r
import javax.security.auth.Subject;\r
import javax.security.auth.callback.CallbackHandler;\r
-import javax.security.auth.login.FailedLoginException;\r
import javax.security.auth.login.LoginException;\r
-import javax.sql.DataSource;\r
-import org.jboss.security.SimpleGroup;\r
-import org.jboss.security.SimplePrincipal;\r
-import org.jboss.security.auth.spi.DatabaseServerLoginModule;\r
+import org.jboss.security.auth.spi.UsernamePasswordLoginModule;\r
\r
/**\r
* CollectionSpace default identity provider supporting multi-tenancy\r
* @author\r
*/\r
-public class CSpaceDBLoginModule extends DatabaseServerLoginModule {\r
-\r
- protected String tenantQuery = "select tenantid from users where username=?";\r
+public class CSpaceDBLoginModule extends UsernamePasswordLoginModule {\r
+\r
+ private DatabaseRealm realm;\r
+\r
+ /**\r
+ * Initialize CSpaceDBLoginModule\r
+ *\r
+ * @param options -\r
+ * dsJndiName: The name of the DataSource of the database containing the\r
+ * Principals, Roles tables\r
+ * principalsQuery: The prepared statement query, equivalent to:\r
+ * "select Password from Principals where PrincipalID=?"\r
+ * rolesQuery: The prepared statement query, equivalent to:\r
+ * "select Role, RoleGroup from Roles where PrincipalID=?"\r
+ * tenantsQuery:\r
+ * "select TenantId, TenantName, TenantGroup from Tenants where PrincipalID=?"\r
+ */\r
+ public void initialize(Subject subject, CallbackHandler callbackHandler,\r
+ Map sharedState, Map options) {\r
+ super.initialize(subject, callbackHandler, sharedState, options);\r
+ realm = new DatabaseRealm(options);\r
+ }\r
//disabled due to classloading problem\r
// private Logger logger = LoggerFactory.getLogger(CSpaceDBLoginModule.class);\r
- private String tenantId;\r
\r
protected String getUsersPassword() throws LoginException {\r
\r
String username = getUsername();\r
String password = null;\r
- Connection conn = null;\r
- PreparedStatement ps = null;\r
- ResultSet rs = null;\r
try {\r
- conn = getConnection();\r
- // Get the password\r
- if (log.isDebugEnabled()) {\r
- log.debug("Executing query: " + principalsQuery + ", with username: " + username);\r
- }\r
- ps = conn.prepareStatement(principalsQuery);\r
- ps.setString(1, username);\r
- rs = ps.executeQuery();\r
- if (rs.next() == false) {\r
- if (log.isDebugEnabled()) {\r
- log.debug(principalsQuery + " returned no matches from db");\r
- }\r
- throw new FailedLoginException("No matching username found");\r
- }\r
-\r
- password = rs.getString(1);\r
+ password = realm.getUsersPassword(username);\r
password = convertRawPassword(password);\r
if (log.isDebugEnabled()) {\r
log.debug("Obtained user password");\r
}\r
- tenantId = rs.getString(2);\r
- if (log.isDebugEnabled()) {\r
- log.debug("Obtained tenantId");\r
- }\r
- CSpacePrincipal principal = (CSpacePrincipal)getIdentity();\r
- principal.setTenantId(tenantId);\r
- } catch (SQLException ex) {\r
- LoginException le = new LoginException("Query failed");\r
- le.initCause(ex);\r
- throw le;\r
+ } catch (LoginException lex) {\r
+ throw lex;\r
} catch (Exception ex) {\r
LoginException le = new LoginException("Unknown Exception");\r
le.initCause(ex);\r
throw le;\r
- } finally {\r
- if (rs != null) {\r
- try {\r
- rs.close();\r
- } catch (SQLException e) {\r
- }\r
- }\r
- if (ps != null) {\r
- try {\r
- ps.close();\r
- } catch (SQLException e) {\r
- }\r
- }\r
- if (conn != null) {\r
- try {\r
- conn.close();\r
- } catch (SQLException ex) {\r
- }\r
- }\r
}\r
return password;\r
}\r
*/\r
protected Group[] getRoleSets() throws LoginException {\r
String username = getUsername();\r
- if (log.isDebugEnabled()) {\r
- log.debug("getRoleSets using rolesQuery: " + rolesQuery + ", username: " + username);\r
- }\r
-\r
- Connection conn = null;\r
- HashMap setsMap = new HashMap();\r
- PreparedStatement ps = null;\r
- ResultSet rs = null;\r
-\r
- try {\r
- conn = getConnection();\r
- // Get the user role names\r
- if (log.isDebugEnabled()) {\r
- log.debug("Executing query: " + rolesQuery + ", with username: " + username);\r
- }\r
\r
- ps = conn.prepareStatement(rolesQuery);\r
- try {\r
- ps.setString(1, username);\r
- ps.setString(2, tenantId);\r
- } catch (ArrayIndexOutOfBoundsException ignore) {\r
- // The query may not have any parameters so just try it\r
- }\r
- rs = ps.executeQuery();\r
- if (rs.next() == false) {\r
- if (log.isDebugEnabled()) {\r
- log.debug("No roles found");\r
- }\r
-// if(aslm.getUnauthenticatedIdentity() == null){\r
-// throw new FailedLoginException("No matching username found in Roles");\r
-// }\r
- /* We are running with an unauthenticatedIdentity so create an\r
- empty Roles set and return.\r
- */\r
-\r
- Group[] roleSets = {new SimpleGroup("Roles")};\r
- return roleSets;\r
- }\r
-\r
- do {\r
- String name = rs.getString(1);\r
- String groupName = rs.getString(2);\r
- if (groupName == null || groupName.length() == 0) {\r
- groupName = "Roles";\r
- }\r
-\r
- Group group = (Group) setsMap.get(groupName);\r
- if (group == null) {\r
- group = new SimpleGroup(groupName);\r
- setsMap.put(groupName, group);\r
- }\r
-\r
- try {\r
-// Principal p = aslm.createIdentity(name);\r
- Principal p = createIdentity(name);\r
- if (log.isDebugEnabled()) {\r
- log.debug("Assign user to role " + name);\r
- }\r
-\r
- group.addMember(p);\r
- } catch (Exception e) {\r
- log.error("Failed to create principal: " + name + " " + e.toString());\r
- }\r
-\r
- } while (rs.next());\r
- } catch (SQLException ex) {\r
- LoginException le = new LoginException("Query failed");\r
- le.initCause(ex);\r
- throw le;\r
- } finally {\r
- if (rs != null) {\r
- try {\r
- rs.close();\r
- } catch (SQLException e) {\r
- }\r
- }\r
- if (ps != null) {\r
- try {\r
- ps.close();\r
- } catch (SQLException e) {\r
- }\r
- }\r
- if (conn != null) {\r
- try {\r
- conn.close();\r
- } catch (Exception ex) {\r
- }\r
- }\r
+ Collection<Group> roles = realm.getRoles(username,\r
+ "org.collectionspace.authentication.CSpacePrincipal",\r
+ "org.jboss.security.SimpleGroup");\r
\r
- }\r
+ Collection<Group> tenants = realm.getTenants(username,\r
+ "org.collectionspace.authentication.CSpacePrincipal",\r
+ "org.jboss.security.SimpleGroup");\r
\r
- Group[] roleSets = new Group[setsMap.size()];\r
- setsMap.values().toArray(roleSets);\r
+ List<Group> all = new ArrayList<Group>();\r
+ all.addAll(roles);\r
+ all.addAll(tenants);\r
+ Group[] roleSets = new Group[all.size()];\r
+ all.toArray(roleSets);\r
return roleSets;\r
}\r
\r
-\r
- private Connection getConnection() throws LoginException, SQLException {\r
- InitialContext ctx = null;\r
- Connection conn = null;\r
- try {\r
- ctx = new InitialContext();\r
- DataSource ds = (DataSource) ctx.lookup(dsJndiName);\r
- if (ds == null) {\r
- throw new IllegalArgumentException("datasource not found: " + dsJndiName);\r
- }\r
- conn = ds.getConnection();\r
- return conn;\r
- } catch (NamingException ex) {\r
- LoginException le = new LoginException("Error looking up DataSource from: " + dsJndiName);\r
- le.initCause(ex);\r
- throw le;\r
- } finally {\r
- if (ctx != null) {\r
- try {\r
- ctx.close();\r
- } catch (Exception e) {\r
- }\r
- }\r
- }\r
-\r
+ /** A hook to allow subclasses to convert a password from the database\r
+ into a plain text string or whatever form is used for matching against\r
+ the user input. It is called from within the getUsersPassword() method.\r
+ @param rawPassword - the password as obtained from the database\r
+ @return the argument rawPassword\r
+ */\r
+ protected String convertRawPassword(String rawPassword) {\r
+ return rawPassword;\r
}\r
}\r
--- /dev/null
+/**
+ * This document is a part of the source code and related artifacts
+ * for CollectionSpace, an open source collections management system
+ * for museums and related institutions:
+
+ * http://www.collectionspace.org
+ * http://wiki.collectionspace.org
+
+ * Copyright 2009 University of California at Berkeley
+
+ * Licensed under the Educational Community License (ECL), Version 2.0.
+ * You may not use this file except in compliance with this License.
+
+ * You may obtain a copy of the ECL 2.0 License at
+
+ * https://source.collectionspace.org/collection-space/LICENSE.txt
+
+ * 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.
+ */
+package org.collectionspace.authentication;
+
+import java.security.Principal;
+import java.security.acl.Group;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Iterator;
+
+/**
+ * A CSpace Principal representing a tenant
+ * A class derived (in principle) from JBoss SimpleGroup and SimplePrincipal
+ * @author
+ */
+public class CSpaceTenant implements Group, Cloneable {
+
+ /** The serialVersionUID */
+ private static final long serialVersionUID = 1L;
+ private String name;
+ private String id;
+ private HashMap members = new HashMap(3);
+
+ public CSpaceTenant(String name, String id) {
+ if(name == null || id == null) {
+ String msg = "CSpaceTenant: invalid argument(s), can't be null" +
+ "name=" + name + " id=" + id;
+ throw new IllegalArgumentException(msg);
+ }
+ this.name = name;
+ this.id = id;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ /**
+ * Adds the specified member to the tenant.
+ * @param user the principal to add to this tenant.
+ * @return true if the member was successfully added,
+ * false if the principal was already a member.
+ */
+ @Override
+ public boolean addMember(Principal user) {
+ boolean isMember = members.containsKey(user);
+ if (isMember == false) {
+ members.put(user, user);
+ }
+ return isMember == false;
+ }
+
+ /**
+ * isMember returns true if the passed principal is a member of the tenant.
+ * This method does a recursive search, so if a principal belongs to a
+ * tenant which is a member of this tenant, true is returned.
+ * @param member the principal whose membership is to be checked.
+ * @return true if the principal is a member of this tenant, false otherwise.
+ */
+ @Override
+ public boolean isMember(Principal member) {
+ // First see if there is a key with the member name
+ boolean isMember = members.containsKey(member);
+ if (isMember == false) { // Check any tenants for membership
+ Collection values = members.values();
+ Iterator iter = values.iterator();
+ while (isMember == false && iter.hasNext()) {
+ Object next = iter.next();
+ if (next instanceof Group) {
+ Group tenant = (Group) next;
+ isMember = tenant.isMember(member);
+ }
+ }
+ }
+ return isMember;
+ }
+
+ /**
+ * members returns an enumeration of the members in the tenant.
+ * The returned objects can be instances of either Principal
+ * or Group (which is a subinterface of Principal).
+ * @return an enumeration of the tenant members.
+ */
+ @Override
+ public Enumeration members() {
+ return Collections.enumeration(members.values());
+ }
+
+ /**
+ * removeMember removes the specified member from the tenant.
+ * @param user the principal to remove from this tenant.
+ * @return true if the principal was removed, or
+ * false if the principal was not a member.
+ */
+ @Override
+ public boolean removeMember(Principal user) {
+ Object prev = members.remove(user);
+ return prev != null;
+ }
+
+ /**
+ * Compare this tenant against another tenant
+ * @return true if name equals another.getName();
+ */
+ @Override
+ public boolean equals(Object another) {
+ if (!(another instanceof CSpaceTenant)) {
+ return false;
+ }
+ String anotherName = ((CSpaceTenant) another).getName();
+ String anotherId = ((CSpaceTenant) another).getId();
+ return name.equals(anotherName) && id.equals(anotherId);
+ }
+
+ @Override
+ public int hashCode() {
+ return (name + id).hashCode();
+ }
+
+ @Override
+ public String toString() {
+ StringBuffer tmp = new StringBuffer(getName());
+ tmp.append("(members:");
+ Iterator iter = members.keySet().iterator();
+ while (iter.hasNext()) {
+ tmp.append(iter.next());
+ tmp.append(',');
+ }
+ tmp.setCharAt(tmp.length() - 1, ')');
+ return tmp.toString();
+ }
+
+ @Override
+ public synchronized Object clone() throws CloneNotSupportedException {
+ CSpaceTenant clone = (CSpaceTenant) super.clone();
+ if (clone != null) {
+ clone.members = (HashMap) this.members.clone();
+ }
+ return clone;
+ }
+}
--- /dev/null
+/**
+ * This document is a part of the source code and related artifacts
+ * for CollectionSpace, an open source collections management system
+ * for museums and related institutions:
+
+ * http://www.collectionspace.org
+ * http://wiki.collectionspace.org
+
+ * Copyright 2009 University of California at Berkeley
+
+ * Licensed under the Educational Community License (ECL), Version 2.0.
+ * You may not use this file except in compliance with this License.
+
+ * You may obtain a copy of the ECL 2.0 License at
+
+ * https://source.collectionspace.org/collection-space/LICENSE.txt
+
+ * 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.
+ *//**
+ * This document is a part of the source code and related artifacts
+ * for CollectionSpace, an open source collections management system
+ * for museums and related institutions:
+
+ * http://www.collectionspace.org
+ * http://wiki.collectionspace.org
+
+ * Copyright 2009 University of California at Berkeley
+
+ * Licensed under the Educational Community License (ECL), Version 2.0.
+ * You may not use this file except in compliance with this License.
+
+ * You may obtain a copy of the ECL 2.0 License at
+
+ * https://source.collectionspace.org/collection-space/LICENSE.txt
+
+ * 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.
+ */
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package org.collectionspace.authentication;
+
+import java.lang.reflect.Constructor;
+import java.security.Principal;
+import java.security.acl.Group;
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import javax.naming.InitialContext;
+import javax.naming.NamingException;
+import javax.security.auth.login.FailedLoginException;
+import javax.security.auth.login.LoginException;
+import javax.sql.DataSource;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * DatabaseRealm provides access to user, password, role, tenant database
+ * @author
+ */
+public class DatabaseRealm {
+
+ private static Log log = LogFactory.getLog(DatabaseRealm.class);
+ private String datasourceName;
+ private String principalsQuery;
+ private String rolesQuery;
+ private String tenantsQuery;
+ private boolean suspendResume;
+
+ /**
+ * create DatabaseRelam
+ * @param datasourceName datasource name
+ */
+ public DatabaseRealm(Map options) {
+ datasourceName = (String) options.get("dsJndiName");
+ if (datasourceName == null) {
+ datasourceName = "java:/DefaultDS";
+ }
+ Object tmp = options.get("principalsQuery");
+ if (tmp != null) {
+ principalsQuery = tmp.toString();
+ }
+ tmp = options.get("rolesQuery");
+ if (tmp != null) {
+ rolesQuery = tmp.toString();
+ }
+ tmp = options.get("tenantsQuery");
+ if (tmp != null) {
+ tenantsQuery = tmp.toString();
+ }
+ tmp = options.get("suspendResume");
+ if (tmp != null) {
+ suspendResume = Boolean.valueOf(tmp.toString()).booleanValue();
+ }
+ if (log.isTraceEnabled()) {
+ log.trace("DatabaseServerLoginModule, dsJndiName=" + datasourceName);
+ log.trace("principalsQuery=" + principalsQuery);
+ log.trace("rolesQuery=" + rolesQuery);
+ log.trace("suspendResume=" + suspendResume);
+ }
+
+ }
+
+ String getUsersPassword(String username) throws LoginException {
+
+ String password = null;
+ Connection conn = null;
+ PreparedStatement ps = null;
+ ResultSet rs = null;
+ try {
+ conn = getConnection();
+ // Get the password
+ if (log.isDebugEnabled()) {
+ log.debug("Executing query: " + principalsQuery + ", with username: " + username);
+ }
+ ps = conn.prepareStatement(principalsQuery);
+ ps.setString(1, username);
+ rs = ps.executeQuery();
+ if (rs.next() == false) {
+ if (log.isDebugEnabled()) {
+ log.debug(principalsQuery + " returned no matches from db");
+ }
+ throw new FailedLoginException("No matching username found");
+ }
+
+ password = rs.getString(1);
+ } catch (SQLException ex) {
+ LoginException le = new LoginException("Query failed");
+ le.initCause(ex);
+ throw le;
+ } catch (Exception ex) {
+ LoginException le = new LoginException("Unknown Exception");
+ le.initCause(ex);
+ throw le;
+ } finally {
+ if (rs != null) {
+ try {
+ rs.close();
+ } catch (SQLException e) {
+ }
+ }
+ if (ps != null) {
+ try {
+ ps.close();
+ } catch (SQLException e) {
+ }
+ }
+ if (conn != null) {
+ try {
+ conn.close();
+ } catch (SQLException ex) {
+ }
+ }
+ }
+ return password;
+ }
+
+ /**
+ * Execute the rolesQuery against the datasourceName to obtain the roles for
+ * the authenticated user.
+ * @return collection containing the roles
+ */
+ Collection<Group> getRoles(String username, String principalClassName, String groupClassName) throws LoginException {
+
+ if (log.isDebugEnabled()) {
+ log.debug("getRoleSets using rolesQuery: " + rolesQuery + ", username: " + username);
+ }
+
+ Connection conn = null;
+ HashMap<String, Group> groupsMap = new HashMap<String, Group>();
+ PreparedStatement ps = null;
+ ResultSet rs = null;
+
+ try {
+ conn = getConnection();
+ // Get the user role names
+ if (log.isDebugEnabled()) {
+ log.debug("Executing query: " + rolesQuery + ", with username: " + username);
+ }
+
+ ps = conn.prepareStatement(rolesQuery);
+ try {
+ ps.setString(1, username);
+ } catch (ArrayIndexOutOfBoundsException ignore) {
+ // The query may not have any parameters so just try it
+ }
+ rs = ps.executeQuery();
+ if (rs.next() == false) {
+ if (log.isDebugEnabled()) {
+ log.debug("No roles found");
+ }
+// if(aslm.getUnauthenticatedIdentity() == null){
+// throw new FailedLoginException("No matching username found in Roles");
+// }
+ /* We are running with an unauthenticatedIdentity so create an
+ empty Roles set and return.
+ */
+
+ Group g = createGroup(groupClassName, "Roles");
+ groupsMap.put(g.getName(), g);
+ return groupsMap.values();
+ }
+
+ do {
+ String roleName = rs.getString(1);
+ String groupName = rs.getString(2);
+ if (groupName == null || groupName.length() == 0) {
+ groupName = "Roles";
+ }
+
+ Group group = (Group) groupsMap.get(groupName);
+ if (group == null) {
+ group = createGroup(groupClassName, groupName);
+ groupsMap.put(groupName, group);
+ }
+
+ try {
+ Principal p = createPrincipal(principalClassName, roleName);
+ if (log.isDebugEnabled()) {
+ log.debug("Assign user to role " + roleName);
+ }
+
+ group.addMember(p);
+ } catch (Exception e) {
+ log.error("Failed to create principal: " + roleName + " " + e.toString());
+ }
+
+ } while (rs.next());
+ } catch (SQLException ex) {
+ LoginException le = new LoginException("Query failed");
+ le.initCause(ex);
+ throw le;
+ } catch (Exception e) {
+ LoginException le = new LoginException("unknown exception");
+ le.initCause(e);
+ throw le;
+ } finally {
+ if (rs != null) {
+ try {
+ rs.close();
+ } catch (SQLException e) {
+ }
+ }
+ if (ps != null) {
+ try {
+ ps.close();
+ } catch (SQLException e) {
+ }
+ }
+ if (conn != null) {
+ try {
+ conn.close();
+ } catch (Exception ex) {
+ }
+ }
+
+ }
+
+ return groupsMap.values();
+
+ }
+
+ /**
+ * Execute the tenantsQuery against the datasourceName to obtain the tenants for
+ * the authenticated user.
+ * @return collection containing the roles
+ */
+ Collection<Group> getTenants(String username, String principalClassName, String groupClassName) throws LoginException {
+
+ if (log.isDebugEnabled()) {
+ log.debug("getTenants using tenantsQuery: " + tenantsQuery + ", username: " + username);
+ }
+
+ Connection conn = null;
+ HashMap<String, Group> groupsMap = new HashMap<String, Group>();
+ PreparedStatement ps = null;
+ ResultSet rs = null;
+
+ try {
+ conn = getConnection();
+ // Get the user role names
+ if (log.isDebugEnabled()) {
+ log.debug("Executing query: " + tenantsQuery + ", with username: " + username);
+ }
+
+ ps = conn.prepareStatement(tenantsQuery);
+ try {
+ ps.setString(1, username);
+ } catch (ArrayIndexOutOfBoundsException ignore) {
+ // The query may not have any parameters so just try it
+ }
+ rs = ps.executeQuery();
+ if (rs.next() == false) {
+ if (log.isDebugEnabled()) {
+ log.debug("No tenants found");
+ }
+ // We are running with an unauthenticatedIdentity so create an
+ // empty Tenants set and return.
+ // FIXME should this be allowed?
+ Group g = createGroup(groupClassName, "Tenants");
+ groupsMap.put(g.getName(), g);
+ return groupsMap.values();
+ }
+
+ do {
+ String tenantId = rs.getString(1);
+ String tenantName = rs.getString(2);
+ String groupName = rs.getString(3);
+ if (groupName == null || groupName.length() == 0) {
+ groupName = "Tenants";
+ }
+
+ Group group = (Group) groupsMap.get(groupName);
+ if (group == null) {
+ group = createGroup(groupClassName, groupName);
+ groupsMap.put(groupName, group);
+ }
+
+ try {
+ Principal p = createTenant(tenantName, tenantId);
+ if (log.isDebugEnabled()) {
+ log.debug("Assign user to tenant " + tenantName);
+ }
+
+ group.addMember(p);
+ } catch (Exception e) {
+ log.error("Failed to create tenant: " + tenantName + " " + e.toString());
+ }
+ } while (rs.next());
+ } catch (SQLException ex) {
+ LoginException le = new LoginException("Query failed");
+ le.initCause(ex);
+ throw le;
+ } catch (Exception e) {
+ LoginException le = new LoginException("unknown exception");
+ le.initCause(e);
+ throw le;
+ } finally {
+ if (rs != null) {
+ try {
+ rs.close();
+ } catch (SQLException e) {
+ }
+ }
+ if (ps != null) {
+ try {
+ ps.close();
+ } catch (SQLException e) {
+ }
+ }
+ if (conn != null) {
+ try {
+ conn.close();
+ } catch (Exception ex) {
+ }
+ }
+
+ }
+
+ return groupsMap.values();
+ }
+
+ private CSpaceTenant createTenant(String name, String id) throws Exception {
+ return new CSpaceTenant(name, id);
+ }
+
+ private Group createGroup(String groupClassName, String name) throws Exception {
+ return (Group) createPrincipal(groupClassName, name);
+ }
+
+ private Principal createPrincipal(String principalClassName, String name) throws Exception {
+ ClassLoader loader = Thread.currentThread().getContextClassLoader();
+ Class clazz = loader.loadClass(principalClassName);
+ Class[] ctorSig = {String.class};
+ Constructor ctor = clazz.getConstructor(ctorSig);
+ Object[] ctorArgs = {name};
+ Principal p = (Principal) ctor.newInstance(ctorArgs);
+ return p;
+ }
+
+ private Connection getConnection() throws LoginException, SQLException {
+ InitialContext ctx = null;
+ Connection conn = null;
+ try {
+ ctx = new InitialContext();
+ DataSource ds = (DataSource) ctx.lookup(getDataSourceName());
+ if (ds == null) {
+ throw new IllegalArgumentException("datasource not found: " + getDataSourceName());
+ }
+ conn = ds.getConnection();
+ return conn;
+ } catch (NamingException ex) {
+ LoginException le = new LoginException("Error looking up DataSource from: " + getDataSourceName());
+ le.initCause(ex);
+ throw le;
+ } finally {
+ if (ctx != null) {
+ try {
+ ctx.close();
+ } catch (Exception e) {
+ }
+ }
+ }
+
+ }
+
+ /**
+ * @return the datasourceName
+ */
+ public String getDataSourceName() {
+ return datasourceName;
+ }
+
+ /**
+ * @return the principalQuery
+ */
+ public String getPrincipalQuery() {
+ return principalsQuery;
+ }
+
+ /**
+ * @param principalQuery the principalQuery to set
+ */
+ public void setPrincipalQuery(String principalQuery) {
+ this.principalsQuery = principalQuery;
+ }
+
+ /**
+ * @return the roleQuery
+ */
+ public String getRoleQuery() {
+ return rolesQuery;
+ }
+
+ /**
+ * @param roleQuery the roleQuery to set
+ */
+ public void setRoleQuery(String roleQuery) {
+ this.rolesQuery = roleQuery;
+ }
+
+ /**
+ * @return the tenantQuery
+ */
+ public String getTenantQuery() {
+ return tenantsQuery;
+ }
+
+ /**
+ * @param tenantQuery the tenantQuery to set
+ */
+ public void setTenantQuery(String tenantQuery) {
+ this.tenantsQuery = tenantQuery;
+ }
+}
Copyright 2009 University of California at Berkeley
Licensed under the Educational Community License (ECL), Version 2.0.
You may not use this file except in compliance with this License.
-
+
Document : jboss-login-config.xml
Created on : June 19, 2009, 9:58 AM
- Author :
+ Author :
Description:
jboss config for JAAS DatabaseServerLoginModule
-->
<application-policy name="cspace">
<authentication>
<login-module code="org.collectionspace.authentication.CSpaceDBLoginModule"
- flag="required">
+ flag="required">
<module-option name="dsJndiName">CspaceDS</module-option>
<module-option name="hashAlgorithm">SHA-256</module-option>
<module-option name="ignorePasswordCase">false</module-option>
<module-option name = "principalClass">org.collectionspace.authentication.CSpacePrincipal</module-option>
<module-option name="principalsQuery">
- select passwd, tenantid from users where username=?
+ select passwd from users where username=?
</module-option>
<module-option name="rolesQuery">
- select rolename, 'Roles' from users_roles where username=? and tenantid=?
+ select rolename, 'Roles' from users_roles where username=?
+ </module-option>
+ <module-option name="tenantsQuery">
+ select id, name, 'Tenants' from accounts_common a, tenants as t where a.userid=? and a.csid = t.TENANT_ACCOUNTSCOMMON_CSID
</module-option>
</login-module>
</authentication>
<description>\r
collectionspace services main\r
</description>\r
- <!-- set global properties for this build -->\r
+ <!-- set global properties for this build -->\r
<property name="services.trunk" value=".."/>\r
<property file="${services.trunk}/build.properties" />\r
<property name="mvn.opts" value="" />\r
</condition>\r
\r
<target name="package" depends="package-unix,package-windows"\r
- description="Package CollectionSpace Services" />\r
- \r
+ description="Package CollectionSpace Services" />\r
+\r
<target name="package-unix" if="osfamily-unix">\r
<exec executable="mvn" failonerror="true">\r
<arg value="package" />\r
<arg value="${mvn.opts}" />\r
</exec>\r
</target>\r
- \r
+\r
<target name="package-windows" if="osfamily-windows">\r
<exec executable="cmd" failonerror="true">\r
<arg value="/c" />\r
\r
\r
<target name="install" depends="package,install-unix,install-windows"\r
- description="Install" />\r
+ description="Install" />\r
<target name="install-unix" if="osfamily-unix">\r
<exec executable="mvn" failonerror="true">\r
<arg value="install" />\r
</target>\r
\r
<target name="clean" depends="clean-unix,clean-windows"\r
- description="Delete target directories" >\r
+ description="Delete target directories" >\r
<delete dir="${build}"/>\r
</target>\r
<target name="clean-unix" if="osfamily-unix">\r
</target>\r
\r
<target name="create_db"\r
- description="create service-specific tables(s), indices, etc.">\r
+ description="create service-specific tables(s), indices, etc.">\r
<ant antfile="authentication/build.xml" target="create_db" inheritAll="false"/>\r
<ant antfile="account/build.xml" target="create_db" inheritAll="false"/>\r
<ant antfile="id/build.xml" target="create_db" inheritAll="false"/>\r
\r
<!-- this target is called in order based on the dependencies between the services -->\r
<target name="deploy" depends="install"\r
- description="deploy services in ${jboss.server.cspace}">\r
- <ant antfile="common/build.xml" target="deploy" inheritAll="false"/>\r
+ description="deploy services in ${jboss.server.cspace}">\r
<ant antfile="authentication/build.xml" target="deploy" inheritAll="false"/>\r
+ <ant antfile="common/build.xml" target="deploy" inheritAll="false"/>\r
<ant antfile="relation/build.xml" target="deploy" inheritAll="false"/>\r
<ant antfile="id/build.xml" target="deploy" inheritAll="false"/>\r
<ant antfile="collectionobject/build.xml" target="deploy" inheritAll="false"/>\r
\r
<!-- this target is called in revese order of deploy targets -->\r
<target name="undeploy"\r
- description="undeploy services from ${jboss.server.cspace}">\r
+ description="undeploy services from ${jboss.server.cspace}">\r
<ant antfile="JaxRsServiceProvider/build.xml" target="undeploy" inheritAll="false"/>\r
<ant antfile="vocabulary/build.xml" target="undeploy" inheritAll="false"/>\r
<ant antfile="contact/build.xml" target="undeploy" inheritAll="false"/> \r
<ant antfile="collectionobject/build.xml" target="undeploy" inheritAll="false"/>\r
<ant antfile="id/build.xml" target="undeploy" inheritAll="false"/>\r
<ant antfile="relation/build.xml" target="undeploy" inheritAll="false"/>\r
- <ant antfile="authentication/build.xml" target="undeploy" inheritAll="false"/>\r
<ant antfile="common/build.xml" target="undeploy" inheritAll="false"/>\r
+ <ant antfile="authentication/build.xml" target="undeploy" inheritAll="false"/>\r
</target>\r
\r
<target name="hotdeploy" depends="install"\r
- description="deploy services in running ${jboss.server.cspace}">\r
+ description="deploy services in running ${jboss.server.cspace}">\r
<ant antfile="JaxRsServiceProvider/build.xml" target="hotdeploy" inheritAll="false"/>\r
</target>\r
\r
<!-- this target is called in order based on the dependencies between the services -->\r
<target name="dist" depends="package"\r
- description="create distribution for services">\r
+ description="create distribution for services">\r
<ant antfile="common/build.xml" target="dist" inheritAll="false"/>\r
<ant antfile="authentication/build.xml" target="dist" inheritAll="false"/>\r
+ <ant antfile="common/build.xml" target="dist" inheritAll="false"/>\r
<ant antfile="relation/build.xml" target="dist" inheritAll="false"/>\r
<ant antfile="id/build.xml" target="dist" inheritAll="false"/>\r
<ant antfile="collectionobject/build.xml" target="dist" inheritAll="false"/>\r
<ant antfile="acquisition/build.xml" target="dist" inheritAll="false"/>\r
<ant antfile="JaxRsServiceProvider/build.xml" target="dist" inheritAll="false"/>\r
</target>\r
- \r
+\r
<!-- this target is called in order based on the dependencies between the services -->\r
<target name="dist_installer"\r
- description="create distribution for CollectionSpace installer">\r
- \r
+ description="create distribution for CollectionSpace installer">\r
+\r
<!-- copy install scripts, etc. -->\r
<copy todir="${services.trunk}/${dist.installer.services}">\r
<fileset dir="./installer"/>\r
<ant antfile="id/build.xml" target="dist_installer" inheritAll="false"/>\r
<ant antfile="collectionobject/build.xml" target="dist_installer" inheritAll="false"/>\r
<ant antfile="vocabulary/build.xml" target="dist_installer" inheritAll="false"/>\r
-<!--\r
+ <!--\r
<ant antfile="common/build.xml" target="dist_installer" inheritAll="false"/>\r
<ant antfile="authentication/build.xml" target="dist_installer" inheritAll="false"/>\r
<ant antfile="relation/build.xml" target="dist_installer" inheritAll="false"/>\r
--> \r
</target>\r
\r
- \r
+\r
</project>\r
protected final String NON_EXISTENT_ID = createNonExistentIdentifier();
// The HTTP status code expected to be returned in the response,
// from a request made to a service (where relevant).
- int EXPECTED_STATUS_CODE = 0;
+ protected int EXPECTED_STATUS_CODE = 0;
// The generic type of service request being tested
// (e.g. CREATE, UPDATE, DELETE).
//
return sb.toString();
}
- private void banner(String label) {
+ protected void banner(String label) {
if(logger.isDebugEnabled()){
logger.debug("===================================================");
logger.debug(" Test = " + label);
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
package org.collectionspace.services.client.test;
import java.util.Arrays;
* $LastChangedDate$
*/
public enum ServiceRequestType {
-
+
// Define each of the service request types and their valid HTTP status codes.
-
CREATE {
+
@Override
- public int[] validStatusCodes() {
- final int[] STATUS_CODES = {
- Response.Status.CREATED.getStatusCode(),
- Response.Status.BAD_REQUEST.getStatusCode(),
- Response.Status.FORBIDDEN.getStatusCode(),
- Response.Status.CONFLICT.getStatusCode(),
- Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()
- };
- Arrays.sort(STATUS_CODES);
- return STATUS_CODES;
+ public int[] validStatusCodes() {
+ final int[] STATUS_CODES = {
+ Response.Status.CREATED.getStatusCode(),
+ Response.Status.BAD_REQUEST.getStatusCode(),
+ Response.Status.UNAUTHORIZED.getStatusCode(),
+ Response.Status.FORBIDDEN.getStatusCode(),
+ Response.Status.CONFLICT.getStatusCode(),
+ Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()
+ };
+ Arrays.sort(STATUS_CODES);
+ return STATUS_CODES;
}
+
@Override
public boolean isValidStatusCode(int statusCode) {
- if (Arrays.binarySearch(CREATE.validStatusCodes(), statusCode) >= 0) {
- return true;
- } else {
- return false;
- }
+ if (Arrays.binarySearch(CREATE.validStatusCodes(), statusCode) >= 0) {
+ return true;
+ } else {
+ return false;
+ }
}
+
@Override
public String validStatusCodesAsString() {
- return Arrays.toString(CREATE.validStatusCodes());
+ return Arrays.toString(CREATE.validStatusCodes());
}
+
@Override
public String httpMethodName() {
return javax.ws.rs.HttpMethod.POST;
}
- }, // Note that commas are required at the end of each enum block, except the last.
-
-
+ }, // Note that commas are required at the end of each enum block, except the last.
+
READ {
+
@Override
- public int[] validStatusCodes() {
- final int[] STATUS_CODES = {
- Response.Status.OK.getStatusCode(),
- Response.Status.FORBIDDEN.getStatusCode(),
- Response.Status.NOT_FOUND.getStatusCode(),
- Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()
- };
- Arrays.sort(STATUS_CODES);
- return STATUS_CODES;
+ public int[] validStatusCodes() {
+ final int[] STATUS_CODES = {
+ Response.Status.OK.getStatusCode(),
+ Response.Status.UNAUTHORIZED.getStatusCode(),
+ Response.Status.FORBIDDEN.getStatusCode(),
+ Response.Status.NOT_FOUND.getStatusCode(),
+ Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()
+ };
+ Arrays.sort(STATUS_CODES);
+ return STATUS_CODES;
}
+
@Override
public boolean isValidStatusCode(int statusCode) {
- if (Arrays.binarySearch(READ.validStatusCodes(), statusCode) >= 0) {
- return true;
- } else {
- return false;
- }
+ if (Arrays.binarySearch(READ.validStatusCodes(), statusCode) >= 0) {
+ return true;
+ } else {
+ return false;
+ }
}
+
@Override
public String validStatusCodesAsString() {
- return Arrays.toString(READ.validStatusCodes());
+ return Arrays.toString(READ.validStatusCodes());
}
+
@Override
public String httpMethodName() {
return javax.ws.rs.HttpMethod.GET;
}
},
-
-
READ_LIST {
+
@Override
- public int[] validStatusCodes() {
- final int[] STATUS_CODES = {
- Response.Status.OK.getStatusCode(),
- Response.Status.BAD_REQUEST.getStatusCode(),
- Response.Status.FORBIDDEN.getStatusCode(),
- Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()
- };
- Arrays.sort(STATUS_CODES);
- return STATUS_CODES;
+ public int[] validStatusCodes() {
+ final int[] STATUS_CODES = {
+ Response.Status.OK.getStatusCode(),
+ Response.Status.BAD_REQUEST.getStatusCode(),
+ Response.Status.UNAUTHORIZED.getStatusCode(),
+ Response.Status.FORBIDDEN.getStatusCode(),
+ Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()
+ };
+ Arrays.sort(STATUS_CODES);
+ return STATUS_CODES;
}
+
@Override
public boolean isValidStatusCode(int statusCode) {
- if (Arrays.binarySearch(READ_LIST.validStatusCodes(), statusCode) >= 0) {
- return true;
- } else {
- return false;
- }
+ if (Arrays.binarySearch(READ_LIST.validStatusCodes(), statusCode) >= 0) {
+ return true;
+ } else {
+ return false;
+ }
}
+
@Override
public String validStatusCodesAsString() {
- return Arrays.toString(READ_LIST.validStatusCodes());
+ return Arrays.toString(READ_LIST.validStatusCodes());
}
+
@Override
public String httpMethodName() {
return javax.ws.rs.HttpMethod.GET;
}
},
-
-
UPDATE {
+
@Override
- public int[] validStatusCodes() {
- final int[] STATUS_CODES = {
- Response.Status.OK.getStatusCode(),
- Response.Status.BAD_REQUEST.getStatusCode(),
- Response.Status.FORBIDDEN.getStatusCode(),
- Response.Status.NOT_FOUND.getStatusCode(),
- Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()
- };
- Arrays.sort(STATUS_CODES);
- return STATUS_CODES;
+ public int[] validStatusCodes() {
+ final int[] STATUS_CODES = {
+ Response.Status.OK.getStatusCode(),
+ Response.Status.BAD_REQUEST.getStatusCode(),
+ Response.Status.UNAUTHORIZED.getStatusCode(),
+ Response.Status.FORBIDDEN.getStatusCode(),
+ Response.Status.NOT_FOUND.getStatusCode(),
+ Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()
+ };
+ Arrays.sort(STATUS_CODES);
+ return STATUS_CODES;
}
+
@Override
public boolean isValidStatusCode(int statusCode) {
- if (Arrays.binarySearch(UPDATE.validStatusCodes(), statusCode) >= 0) {
- return true;
- } else {
- return false;
- }
+ if (Arrays.binarySearch(UPDATE.validStatusCodes(), statusCode) >= 0) {
+ return true;
+ } else {
+ return false;
+ }
}
+
@Override
public String validStatusCodesAsString() {
- return Arrays.toString(UPDATE.validStatusCodes());
+ return Arrays.toString(UPDATE.validStatusCodes());
}
+
@Override
public String httpMethodName() {
return javax.ws.rs.HttpMethod.PUT;
}
},
-
-
DELETE {
+
@Override
- public int[] validStatusCodes() {
- final int[] STATUS_CODES = {
- Response.Status.OK.getStatusCode(),
- Response.Status.FORBIDDEN.getStatusCode(),
- Response.Status.NOT_FOUND.getStatusCode(),
- Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()
- };
- Arrays.sort(STATUS_CODES);
- return STATUS_CODES;
+ public int[] validStatusCodes() {
+ final int[] STATUS_CODES = {
+ Response.Status.OK.getStatusCode(),
+ Response.Status.UNAUTHORIZED.getStatusCode(),
+ Response.Status.FORBIDDEN.getStatusCode(),
+ Response.Status.NOT_FOUND.getStatusCode(),
+ Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()
+ };
+ Arrays.sort(STATUS_CODES);
+ return STATUS_CODES;
}
+
@Override
public boolean isValidStatusCode(int statusCode) {
- if (Arrays.binarySearch(DELETE.validStatusCodes(), statusCode) >= 0) {
- return true;
- } else {
- return false;
- }
+ if (Arrays.binarySearch(DELETE.validStatusCodes(), statusCode) >= 0) {
+ return true;
+ } else {
+ return false;
+ }
}
+
@Override
public String validStatusCodesAsString() {
- return Arrays.toString(DELETE.validStatusCodes());
+ return Arrays.toString(DELETE.validStatusCodes());
}
+
@Override
public String httpMethodName() {
return javax.ws.rs.HttpMethod.DELETE;
}
},
-
-
// Used by guard code.
NON_EXISTENT {
+
@Override
- public int[] validStatusCodes() {
- final int[] STATUS_CODES = { 0 };
- Arrays.sort(STATUS_CODES);
- return STATUS_CODES;
+ public int[] validStatusCodes() {
+ final int[] STATUS_CODES = {0};
+ Arrays.sort(STATUS_CODES);
+ return STATUS_CODES;
}
+
@Override
public boolean isValidStatusCode(int statusCode) {
- return false;
+ return false;
}
+
@Override
public String validStatusCodesAsString() {
- return Arrays.toString(NON_EXISTENT.validStatusCodes());
+ return Arrays.toString(NON_EXISTENT.validStatusCodes());
}
+
@Override
public String httpMethodName() {
- return "";
+ return "";
}
};
-
+
// Template methods to be implemented by each ServiceRequestType.
-
public abstract int[] validStatusCodes();
-
+
public abstract boolean isValidStatusCode(int statusCode);
-
+
public abstract String validStatusCodesAsString();
public abstract String httpMethodName();
<packaging>jar</packaging>\r
<version>1.0</version>\r
<name>services.common</name>\r
- \r
+\r
<dependencies>\r
- <dependency>\r
- <groupId>com.sun.xml.bind</groupId>\r
- <artifactId>jaxb-impl</artifactId>\r
- </dependency>\r
- <dependency>\r
- <groupId>org.jvnet.jaxb2-commons</groupId>\r
- <artifactId>property-listener-injector</artifactId>\r
- </dependency>\r
- <dependency>\r
- <groupId>org.jvnet.jaxb2_commons</groupId>\r
- <artifactId>runtime</artifactId>\r
- </dependency>\r
- <dependency>\r
- <groupId>org.jboss.resteasy</groupId>\r
- <artifactId>resteasy-jaxrs</artifactId>\r
- <exclusions>\r
- <exclusion>\r
- <groupId>tjws</groupId>\r
- <artifactId>webserver</artifactId>\r
- </exclusion>\r
- </exclusions>\r
- </dependency>\r
- <dependency>\r
- <groupId>org.jboss.resteasy</groupId>\r
- <artifactId>resteasy-jaxb-provider</artifactId>\r
- <version>1.1.GA</version>\r
- </dependency>\r
- <dependency>\r
- <groupId>org.jboss.resteasy</groupId>\r
- <artifactId>resteasy-multipart-provider</artifactId>\r
- <version>1.1.GA</version>\r
- </dependency>\r
\r
<!-- utilities -->\r
<dependency>\r
<groupId>org.slf4j</groupId>\r
<artifactId>slf4j-log4j12</artifactId>\r
</dependency>\r
- <!-- javax -->\r
+ <!-- javax -->\r
\r
<dependency>\r
<groupId>javax.servlet</groupId>\r
<version>2.5</version>\r
<scope>provided</scope>\r
</dependency>\r
- \r
+\r
<dependency>\r
<groupId>javax.security</groupId>\r
<artifactId>jaas</artifactId>\r
<groupId>javax.security</groupId>\r
<artifactId>jacc</artifactId>\r
<version>1.0</version>\r
- <scope>provided</scope>\r
+ <scope>provided</scope>\r
</dependency>\r
<!--\r
<dependency>\r
<scope>provided</scope>\r
</dependency>\r
-->\r
+ <dependency>\r
+ <groupId>mysql</groupId>\r
+ <artifactId>mysql-connector-java</artifactId>\r
+ </dependency>\r
<dependency>\r
<groupId>javax.persistence</groupId>\r
<artifactId>persistence-api</artifactId>\r
</dependency>\r
+\r
+ <dependency>\r
+ <groupId>com.sun.xml.bind</groupId>\r
+ <artifactId>jaxb-impl</artifactId>\r
+ </dependency>\r
+ <dependency>\r
+ <groupId>org.jvnet.jaxb2-commons</groupId>\r
+ <artifactId>property-listener-injector</artifactId>\r
+ </dependency>\r
+ <dependency>\r
+ <groupId>org.jvnet.jaxb2_commons</groupId>\r
+ <artifactId>runtime</artifactId>\r
+ </dependency>\r
+\r
+ <!-- jboss -->\r
+ <dependency>\r
+ <groupId>org.jboss.resteasy</groupId>\r
+ <artifactId>resteasy-jaxrs</artifactId>\r
+ <exclusions>\r
+ <exclusion>\r
+ <groupId>tjws</groupId>\r
+ <artifactId>webserver</artifactId>\r
+ </exclusion>\r
+ </exclusions>\r
+ </dependency>\r
+ <dependency>\r
+ <groupId>org.jboss.resteasy</groupId>\r
+ <artifactId>resteasy-jaxb-provider</artifactId>\r
+ <version>1.1.GA</version>\r
+ </dependency>\r
+ <dependency>\r
+ <groupId>org.jboss.resteasy</groupId>\r
+ <artifactId>resteasy-multipart-provider</artifactId>\r
+ <version>1.1.GA</version>\r
+ </dependency>\r
+\r
<dependency>\r
<groupId>org.hibernate</groupId>\r
<artifactId>hibernate-entitymanager</artifactId>\r
<version>1.1.1</version>\r
</dependency>\r
\r
-\r
+ <dependency>\r
+ <groupId>org.collectionspace.services</groupId>\r
+ <artifactId>org.collectionspace.services.authentication.jaxb</artifactId>\r
+ <version>1.0</version>\r
+ <scope>provided</scope>\r
+ </dependency>\r
+ <dependency>\r
+ <groupId>org.collectionspace.services</groupId>\r
+ <artifactId>org.collectionspace.services.authentication.service</artifactId>\r
+ <version>1.0</version>\r
+ <scope>provided</scope>\r
+ </dependency>\r
</dependencies>\r
- \r
+\r
<build>\r
<finalName>collectionspace-services-common</finalName>\r
<plugins>\r
<plugin>\r
<groupId>org.jvnet.jaxb2.maven2</groupId>\r
<artifactId>maven-jaxb2-plugin</artifactId>\r
+ <!-- version is very important here as we want to explicitly\r
+ use jaxb2 plugin only and not jaxb2 bundled with hyperjaxb3\r
+ that does not allow to invoke generate from base plugin -->\r
+ <version>0.7.0</version>\r
<executions>\r
<execution>\r
<goals>\r
<arg>-XtoString</arg>\r
<arg>-Xinject-listener-code</arg>\r
\r
- <!-- <arg>-Xcollection-setter-injector</arg>\r
+ <!-- <arg>-Xcollection-setter-injector</arg>\r
<arg>-Xfluent-api</arg> -->\r
</args>\r
<plugins>\r
<plugin>\r
<groupId>\r
- org.jvnet.jaxb2_commons\r
+ org.jvnet.jaxb2_commons\r
</groupId>\r
<artifactId>basic</artifactId>\r
<version>0.4.1</version>\r
</plugin>\r
<plugin>\r
<groupId>\r
- org.jvnet.jaxb2-commons\r
+ org.jvnet.jaxb2-commons\r
</groupId>\r
<artifactId>\r
- property-listener-injector\r
+ property-listener-injector\r
</artifactId>\r
<version>1.0</version>\r
</plugin>\r
*/
package org.collectionspace.services.common.context;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.security.Principal;
+import java.security.acl.Group;
+import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.security.auth.Subject;
import javax.security.jacc.PolicyContext;
import javax.security.jacc.PolicyContextException;
+import org.collectionspace.authentication.CSpaceTenant;
import org.collectionspace.services.common.ClientType;
import org.collectionspace.services.common.ServiceMain;
ServiceMain.getInstance().getTenantBindingConfigReader();
//FIXME retrieveTenantId is not working consistently in non-auth mode
//TODO: get tenant binding from security context
- String tenantId = null; //retrieveTenantId();
+ String tenantId = retrieveTenantId();
if (tenantId == null) {
//for testing purposes
tenantId = "1"; //hardcoded for movingimages.us
}
tenantBinding = tReader.getTenantBinding(tenantId);
if (tenantBinding == null) {
- String msg = "No tenant binding found while processing request for " +
- serviceName;
+ String msg = "No tenant binding found for tenantId=" + tenantId +
+ " while processing request for service= " + serviceName;
logger.error(msg);
throw new IllegalStateException(msg);
}
serviceBinding = tReader.getServiceBinding(tenantId, serviceName);
if (serviceBinding == null) {
- String msg = "No service binding found while processing request for " +
- serviceName + " for tenant id=" + getTenantId() +
- " name=" + getTenantName();
+ String msg = "No service binding found while processing request for "
+ + serviceName + " for tenant id=" + getTenantId()
+ + " name=" + getTenantName();
logger.error(msg);
throw new IllegalStateException(msg);
}
if (logger.isDebugEnabled()) {
- logger.debug("tenantId=" + tenantId +
- " service binding=" + serviceBinding.getName());
+ logger.debug("tenantId=" + tenantId
+ + " service binding=" + serviceBinding.getName());
}
}
String tenantId = null;
Subject caller = null;
- Set<Principal> principals = null;
+ Set<Group> groups = null;
try {
caller = (Subject) PolicyContext.getContext(SUBJECT_CONTEXT_KEY);
if (caller == null) {
//logger.warn("security not enabled...");
return tenantId;
}
- principals = caller.getPrincipals(Principal.class);
- if (principals != null && principals.size() == 0) {
+ groups = caller.getPrincipals(Group.class);
+ if (groups != null && groups.size() == 0) {
//TODO: find out why subject is not null
if (logger.isDebugEnabled()) {
- logger.debug("weird case where subject is not null and there are no principals");
+ logger.debug("no tenant(s) found!");
}
return tenantId;
}
logger.error(msg, pce);
throw new UnauthorizedException(msg);
}
- for (Principal p : principals) {
- try {
- Method m = p.getClass().getMethod("getTenantId");
- Object r = m.invoke(p);
- if (logger.isDebugEnabled()) {
- logger.debug("retrieved tenantid=" + r +
- " for principal=" + p.getName());
+ for (Group g : groups) {
+ if ("Tenants".equals(g.getName())) {
+ Enumeration members = g.members();
+ while (members.hasMoreElements()) {
+ CSpaceTenant tenant = (CSpaceTenant) members.nextElement();
+ tenantId = tenant.getId();
+ if (logger.isDebugEnabled()) {
+ logger.debug("found tenant id=" + tenant.getId()
+ + " name=" + tenant.getName());
+ }
}
- tenantId = (String) r;
- break;
- } catch (Exception e) {
- //continue with next principal
}
}
+ //TODO: if a user is associated with more than one tenants, the tenant
+ //id should be matched with sent over the wire
if (tenantId == null) {
String msg = "Could not find tenant context";
logger.error(msg);
public static final String PART_COMMON_LABEL = "common";
/**
- * getTenantId get tenant id
+ * getTenantId get id of tenant for which service is accessed
* @return tenant id
*/
public String getTenantId();
<name>services.main</name>
<modules>
- <!-- add modules below in the order based on dependencies -->
<module>authentication</module>
<module>common</module>
<!-- module>account</module -->