Skip to content

Commit

Permalink
Merge branch '4.2.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
hplahar committed May 29, 2015
2 parents 9a9cdfa + 87636fb commit 3a93b29
Show file tree
Hide file tree
Showing 90 changed files with 2,367 additions and 1,640 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ war/
*.class
data/
ice.iml
*.pem
22 changes: 0 additions & 22 deletions README.md

This file was deleted.

86 changes: 86 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
ICE
===

Inventory of Composable Elements (ICE) is an open source registry
software for biological parts developed by the `Joint
BioEnergy Institute <http://www.jbei.org/>`__. It is a Web application used by laboratories to track and search their
constructs.

ICE is distributed under the Modified BSD license. See LICENSE.txt and LIBRARY_LICENSES.txt for details.

You can try out the software at our `Public
Registry <http://public-registry.jbei.org>`__.

Documentation for ICE Users
-------------

Read the `Manual <https://jbei.github.io/ice/>`__ for installation and usage instructions.


Documentation for ICE developers
--------------------------------

Requirements
~~~~~~~~~~~~
To set up a development environment for ICE you will need to install:

* `BLAST+ <http://blast.ncbi.nlm.nih.gov/Blast.cgi?PAGE_TYPE=BlastDocs&DOC_TYPE=Download>`__ ≥ 2.2.28
* `Java JDK 7 <http://www.oracle.com/technetwork/java/javase/downloads/jdk7-downloads-1880260.html>`__
* `Maven <https://maven.apache.org/download.cgi>`__ ≥ 3.0

If you use a Debian-like operating system, the following command will install all the requirements

::

sudo apt-get install ncbi-blast+ default-jdk maven


Set Up
~~~~~~
1. Checkout the code and enter the repository

::

git checkout https://github.com/JBEI/ice.git
cd ice

2. Since the application requires an SSL certificate, generate one that the Jetty Web server can use this command. When prompted for a password, enter **changeit**

::

keytool -genkey -alias tomcat -keyalg RSA -keystore ./.keystore

3. Start Jetty

::

mvn jetty:run

4. Point your browser to https://localhost:8443/ to access the application

Testing
~~~~~~~
To run the unit test suite

::

mvn test

Links
-----

* `ICE Google Group <http://groups.google.com/group/gd-ice>`__
* `Releases <https://github.com/JBEI/ice/releases>`__: Download the war file associated with the latest release
* `REST API WADL <https://public-registry.jbei.org/rest/application.wadl>`__

Related Projects
----------------

`The VectorEditor project <https://github.com/JBEI/vectoreditor/>`__ is
used in ICE to display and edit sequences. It also contains other
modules such as sequence checker.

|Build Status|

.. |Build Status| image:: https://travis-ci.org/JBEI/ice.svg?branch=dev
:target: https://travis-ci.org/JBEI/ice
14 changes: 13 additions & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<groupId>org.jbei</groupId>
<artifactId>ice</artifactId>
<packaging>war</packaging>
<version>4.1.18</version>
<version>4.2.0</version>
<name>ice</name>
<description>Inventory of Composable Elements (ICE) for Synthetic Biology</description>
<repositories>
Expand Down Expand Up @@ -187,6 +187,18 @@
<configuration>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.6</version>
<configuration>
<webResources>
<resource>
<directory>src/main/resources/aws</directory>
</resource>
</webResources>
</configuration>
</plugin>
</plugins>
</build>
<properties>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,28 +1,27 @@
package org.jbei.ice.lib.account;

import org.jbei.ice.lib.utils.UtilityException;

import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.xml.bind.DatatypeConverter;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;
import java.util.UUID;

/**
* Utility class for handling account passwords
*
* @author Hector Plahar
*/
public class PasswordUtil {
public class TokenHash {

private static final int HASH_BYTE_SIZE = 160;
private static final int SALT_BYTE_SIZE = 32;
private static final int PBKDF2_ITERATIONS = 20000;

public static String encryptPassword(String password, String salt) throws UtilityException {
public TokenHash() {
}

public String encryptPassword(String password, String salt) {
if (password == null || password.trim().isEmpty() || salt == null || salt.trim().isEmpty())
throw new NullPointerException("Password and/or salt cannot be empty");

Expand All @@ -31,20 +30,23 @@ public static String encryptPassword(String password, String salt) throws Utilit
try {
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
byte[] hash = keyFactory.generateSecret(spec).getEncoded();
return DatatypeConverter.printHexBinary(hash);
return DatatypeConverter.printBase64Binary(hash);
} catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
throw new UtilityException(e);
return null;
}
}

public static String generateSalt() {
public String generateSalt() {
SecureRandom random = new SecureRandom();
byte[] salt = new byte[SALT_BYTE_SIZE];
random.nextBytes(salt);
return DatatypeConverter.printHexBinary(salt);
return DatatypeConverter.printBase64Binary(salt);
}

public static String generateTemporaryPassword() {
return UUID.randomUUID().toString().substring(24);
public String generateRandomToken() {
SecureRandom random = new SecureRandom();
byte[] salt = new byte[256];
random.nextBytes(salt);
return DatatypeConverter.printBase64Binary(salt);
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package org.jbei.ice.lib.account.authentication;

import org.jbei.ice.lib.account.AccountController;
import org.jbei.ice.lib.account.AccountUtils;
import org.jbei.ice.lib.account.model.Account;
import org.jbei.ice.lib.common.logging.Logger;
Expand All @@ -22,8 +21,7 @@ public String authenticates(String userId, String password) throws Authenticatio
if (userId == null || password == null)
throw new AuthenticationException("Invalid username and password");

AccountController controller = new AccountController();
Account account = controller.getByEmail(userId);
Account account = DAOFactory.getAccountDAO().getByEmail(userId);
if (account == null || !isValidPassword(account, password))
return null;
return account.getEmail();
Expand Down
48 changes: 32 additions & 16 deletions src/main/java/org/jbei/ice/lib/bulkupload/BulkEntryCreator.java
Original file line number Diff line number Diff line change
Expand Up @@ -92,24 +92,35 @@ protected PartData createEntryForUpload(String userId, PartData data, BulkUpload
entry.setOwner(account.getFullName());
entry.setOwnerEmail(account.getEmail());

// check if there is any linked parts. create if so (expect a max of 1)
// check if there is any linked parts.
if (data.getLinkedParts() != null && data.getLinkedParts().size() > 0) {
// create linked
PartData linked = data.getLinkedParts().get(0);
Entry linkedEntry = InfoToModelFactory.infoToEntry(linked);
if (linkedEntry != null) {
linkedEntry.setVisibility(Visibility.DRAFT.getValue());
linkedEntry.setOwner(account.getFullName());
linkedEntry.setOwnerEmail(account.getEmail());
linkedEntry = entryDAO.create(linkedEntry);

linked.setId(linkedEntry.getId());
linked.setModificationTime(linkedEntry.getModificationTime().getTime());
data.getLinkedParts().clear();
data.getLinkedParts().add(linked);

// link to main entry in the database
entry.getLinkedEntries().add(linkedEntry);

// check if linking to existing
if (StringUtils.isEmpty(linked.getPartId())) {
// create new

Entry linkedEntry = InfoToModelFactory.infoToEntry(linked);
if (linkedEntry != null) {
linkedEntry.setVisibility(Visibility.DRAFT.getValue());
linkedEntry.setOwner(account.getFullName());
linkedEntry.setOwnerEmail(account.getEmail());
linkedEntry = entryDAO.create(linkedEntry);

linked.setId(linkedEntry.getId());
linked.setModificationTime(linkedEntry.getModificationTime().getTime());
data.getLinkedParts().clear();
data.getLinkedParts().add(linked);

// link to main entry in the database
entry.getLinkedEntries().add(linkedEntry);
}
} else {
// link existing
Entry linkedEntry = entryDAO.getByPartNumber(linked.getPartId());
if (!entry.getLinkedEntries().contains(linkedEntry)) {
entry.getLinkedEntries().add(linkedEntry);
}
}
}

Expand Down Expand Up @@ -157,6 +168,11 @@ protected PartData doUpdate(String userId, Entry entry, PartData data) {
// retrieve the entry (this is the only time you can create another entry on update)
PartData linkedPartData = data.getLinkedParts().get(0); // bulk upload can only link 1
Entry linkedEntry = entryDAO.get(linkedPartData.getId());
if (linkedEntry == null && !StringUtils.isEmpty(linkedPartData.getPartId())) {
// try partId
linkedEntry = entryDAO.getByPartNumber(linkedPartData.getPartId());
}

if (linkedEntry == null && (linkedEntry = InfoToModelFactory.infoToEntry(linkedPartData)) != null) {
linkedEntry.setVisibility(Visibility.DRAFT.getValue());
Account account = accountController.getByEmail(userId);
Expand Down
11 changes: 0 additions & 11 deletions src/main/java/org/jbei/ice/lib/bulkupload/BulkUpload.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import org.jbei.ice.lib.access.Permission;
import org.jbei.ice.lib.account.AccountTransfer;
import org.jbei.ice.lib.account.model.Account;
import org.jbei.ice.lib.account.model.Preference;
import org.jbei.ice.lib.dao.IDataModel;
import org.jbei.ice.lib.entry.model.Entry;

Expand Down Expand Up @@ -58,12 +57,6 @@ public class BulkUpload implements IDataModel {
inverseJoinColumns = {@JoinColumn(name = "entry_id", nullable = false)})
private Set<Entry> contents = new HashSet<>();

@OneToMany(fetch = FetchType.LAZY, cascade = {CascadeType.REMOVE, CascadeType.MERGE, CascadeType.PERSIST})
@JoinTable(name = "bulk_upload_preferences",
joinColumns = {@JoinColumn(name = "bulk_upload_id", nullable = false)},
inverseJoinColumns = {@JoinColumn(name = "preference_id", nullable = false)})
private Set<Preference> preferences = new HashSet<>();

@OneToMany(cascade = {CascadeType.PERSIST, CascadeType.REMOVE, CascadeType.MERGE})
@JoinTable(name = "bulk_upload_permissions",
joinColumns = {@JoinColumn(name = "bulk_upload_id", nullable = false)},
Expand Down Expand Up @@ -125,10 +118,6 @@ public void setImportType(String importType) {
this.importType = importType;
}

public Set<Preference> getPreferences() {
return preferences;
}

public BulkUploadStatus getStatus() {
return status;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -529,6 +529,19 @@ public boolean deleteAttachment(String userId, long bulkUploadId, long entryId)
return true;
}

public boolean deleteEntry(String userId, long uploadId, long entryId) {
try {
BulkUpload upload = dao.get(uploadId);
Entry entry = new EntryDAO().get(entryId);
authorization.expectWrite(userId, upload);
upload.getContents().remove(entry);
return true;
} catch (Exception e) {
Logger.error(e);
return false;
}
}

public List<AccessPermission> getUploadPermissions(String userId, long uploadId) {
List<AccessPermission> permissions = new ArrayList<>();
BulkUpload upload = dao.get(uploadId);
Expand Down Expand Up @@ -599,4 +612,32 @@ public boolean deletePermission(String userId, long uploadId, long permissionId)
DAOFactory.getPermissionDAO().delete(toDelete);
return dao.update(upload) != null;
}

/**
* Retrieves part numbers that match the token passed in the parameter, that are compatible with the type
* in the parameter. Two entry types are compatible if they can be associated with specific entries (as descendants)
* in a hierarchical relationship
*
* @param type type of entry the part numbers must be compatible with
* @param token part number token to match
* @param limit maximum number of matches to return
* @return list of part numbers that can be linked to the type of entry
*/
public ArrayList<String> getMatchingPartNumbersForLinks(EntryType type, String token, int limit) {
ArrayList<String> dataList = new ArrayList<>();
if (token == null)
return dataList;

Set<String> compatibleTypes = new HashSet<>();
compatibleTypes.add(type.getName());
compatibleTypes.add(EntryType.PART.getName());
if (type == EntryType.STRAIN)
compatibleTypes.add(EntryType.PLASMID.getName());

token = token.replaceAll("'", "");
for (Entry entry : DAOFactory.getEntryDAO().getMatchingEntryPartNumbers(token, limit, compatibleTypes)) {
dataList.add(entry.getPartNumber());
}
return dataList;
}
}
Loading

0 comments on commit 3a93b29

Please sign in to comment.