Search in sources :

Example 1 with AttachmentValue

use of org.activityinfo.model.type.attachment.AttachmentValue in project activityinfo by bedatadriven.

the class ImageUploadFieldWidget method fireValueChanged.

public void fireValueChanged() {
    AttachmentValue attachmentValue = new AttachmentValue();
    if (uploader.getAttachment() != null && !Strings.isNullOrEmpty(uploader.getAttachment().getBlobId())) {
        attachmentValue.getValues().add(uploader.getAttachment());
    }
    valueUpdater.update(attachmentValue);
}
Also used : AttachmentValue(org.activityinfo.model.type.attachment.AttachmentValue)

Example 2 with AttachmentValue

use of org.activityinfo.model.type.attachment.AttachmentValue in project activityinfo by bedatadriven.

the class GcsBlobFieldStorageServiceTest method blobPermissionAttack.

/**
 * 1. user1 : persist blob with FormInstance1 (FormClass1) user1
 * 2. user2 : persist the same blob with FormInstance2 (FormClass2) -> try to steal blob access
 */
@Test
@OnDataSet("/dbunit/sites-simple-blob-security.db.xml")
public void blobPermissionAttack() throws IOException {
    blobService.setTestBucketName();
    int activityId = 1;
    int databaseId = 1;
    int locationType = 10;
    ResourceId attachmentFieldId = ResourceId.generateFieldId(AttachmentType.TYPE_CLASS);
    FormClass formClass = addAttachmentField(activityId, attachmentFieldId);
    blobId = BlobId.generate();
    blobService.put(user, "attachment;filename=" + FILE_NAME, MimeTypeUtil.mimeTypeFromFileName(FILE_NAME), blobId, formClass.getId(), GcsBlobFieldStorageServiceTest.class.getResourceAsStream("goabout.png"));
    FormInstance instance = new FormInstance(CuidAdapter.cuid(SITE_DOMAIN, new KeyGenerator().generateInt()), formClass.getId());
    Attachment attachment = new Attachment();
    attachment.setMimeType(MimeTypeUtil.mimeTypeFromFileName(FILE_NAME));
    attachment.setBlobId(blobId.asString());
    attachment.setFilename(FILE_NAME);
    AttachmentValue attachmentValue = new AttachmentValue();
    attachmentValue.getValues().add(attachment);
    instance.set(indicatorField(1), 1);
    instance.set(indicatorField(2), 2);
    instance.set(attachmentFieldId, attachmentValue);
    instance.set(locationField(activityId), locationRef(CuidAdapter.locationFormClass(locationType), 1));
    instance.set(partnerField(activityId), partnerRef(databaseId, 1));
    instance.set(projectField(activityId), projectRef(databaseId, 1));
    instance.set(field(formClass.getId(), START_DATE_FIELD), new LocalDate(2014, 1, 1));
    instance.set(field(formClass.getId(), END_DATE_FIELD), new LocalDate(2014, 1, 1));
    instance.set(field(formClass.getId(), COMMENT_FIELD), "My comment");
    assertResolves(locator.persist(instance));
    assertInstanceExists(formClass.getId(), instance.getId());
    AuthenticationModuleStub.setUserId(USER_WITHOUT_ACCESS_TO_DB_1);
    int anotherActivityId = 32;
    ResourceId newAttachmentFieldId = ResourceId.generateFieldId(AttachmentType.TYPE_CLASS);
    addAttachmentField(anotherActivityId, newAttachmentFieldId);
    instance.setId(CuidAdapter.cuid(SITE_DOMAIN, new KeyGenerator().generateInt()));
    instance.setClassId(CuidAdapter.activityFormClass(anotherActivityId));
    instance.set(newAttachmentFieldId, attachmentValue);
    instance.set(field(instance.getFormId(), START_DATE_FIELD), new LocalDate(2014, 1, 1));
    instance.set(field(instance.getFormId(), END_DATE_FIELD), new LocalDate(2014, 1, 1));
    instance.set(partnerField(anotherActivityId), partnerRef(databaseId, 1));
    boolean persisted = true;
    try {
        // this must fail because of blob permission check
        assertResolves(locator.persist(instance));
    } catch (RuntimeException e) {
        e.printStackTrace();
        persisted = false;
    }
    assertFalse("Access to blob is stolen! Permissions check for blobs is broken.", persisted);
}
Also used : AttachmentValue(org.activityinfo.model.type.attachment.AttachmentValue) ResourceId(org.activityinfo.model.resource.ResourceId) FormClass(org.activityinfo.model.form.FormClass) Attachment(org.activityinfo.model.type.attachment.Attachment) FormInstance(org.activityinfo.model.form.FormInstance) KeyGenerator(org.activityinfo.model.legacy.KeyGenerator) LocalDate(org.activityinfo.model.type.time.LocalDate) OnDataSet(org.activityinfo.server.database.OnDataSet) Test(org.junit.Test)

Example 3 with AttachmentValue

use of org.activityinfo.model.type.attachment.AttachmentValue in project activityinfo by bedatadriven.

the class XFormSubmissionResource method submit.

@POST
@Consumes(MediaType.MULTIPART_FORM_DATA)
@Produces(MediaType.TEXT_XML)
public Response submit(byte[] bytes) {
    XFormInstance instance = new XFormInstanceImpl(bytes);
    AuthenticatedUser user = authenticationTokenService.authenticate(instance.getAuthenticationToken());
    FormClass formClass = locator.getFormClass(instance.getFormClassId());
    ResourceId formId = newLegacyFormInstanceId(formClass.getId());
    FormInstance formInstance = new FormInstance(formId, formClass.getId());
    String instanceId = instance.getId();
    LOGGER.log(Level.INFO, "Saving XForm " + instance.getId() + " as " + formId);
    for (FormField formField : formClass.getFields()) {
        if (formField.getType().isUpdatable()) {
            Optional<Element> element = instance.getFieldContent(formField.getId());
            if (element.isPresent()) {
                formInstance.set(formField.getId(), tryParse(formInstance, formField, element.get()));
            } else if (isLocation(formClass, formField)) {
                FieldType fieldType = formField.getType();
                Optional<Element> gpsField = instance.getFieldContent(field(formClass.getId(), GPS_FIELD));
                Optional<Element> nameField = instance.getFieldContent(field(formClass.getId(), LOCATION_NAME_FIELD));
                if (fieldType instanceof ReferenceType && gpsField.isPresent() && nameField.isPresent()) {
                    ResourceId locationFieldId = field(formClass.getId(), LOCATION_FIELD);
                    int newLocationId = new KeyGenerator().generateInt();
                    ReferenceType locationRefType = (ReferenceType) fieldType;
                    if (locationRefType.getRange().isEmpty()) {
                        throw new IllegalStateException("Location field has empty range");
                    }
                    ResourceId locationFormId = locationRefType.getRange().iterator().next();
                    int locationTypeId = getLegacyIdFromCuid(locationFormId);
                    FieldValue fieldValue = new ReferenceValue(new RecordRef(locationFormId, locationInstanceId(newLocationId)));
                    String name = OdkHelper.extractText(nameField.get());
                    if (Strings.isNullOrEmpty(name)) {
                        throw new WebApplicationException(Response.status(BAD_REQUEST).entity("Name value for location field is blank. ").build());
                    }
                    Optional<GeoPoint> geoPoint = parseLocation(gpsField);
                    formInstance.set(locationFieldId, fieldValue);
                    createLocation(newLocationId, locationTypeId, name, geoPoint);
                }
            }
        }
    }
    ensurePartnerIsSet(formClass, formInstance);
    if (!instanceIdService.exists(instanceId)) {
        for (FieldValue fieldValue : formInstance.getFieldValueMap().values()) {
            if (fieldValue instanceof AttachmentValue) {
                persist(user, instance, (AttachmentValue) fieldValue);
            }
        }
        locator.persist(formInstance);
        instanceIdService.submit(instanceId);
    }
    // Backup the original XForm in case something went wrong with processing
    submissionArchiver.backup(formClass.getId(), formId, ByteSource.wrap(bytes));
    return Response.status(CREATED).build();
}
Also used : AttachmentValue(org.activityinfo.model.type.attachment.AttachmentValue) Optional(com.google.common.base.Optional) Element(org.w3c.dom.Element) AuthenticatedUser(org.activityinfo.legacy.shared.AuthenticatedUser) ResourceId(org.activityinfo.model.resource.ResourceId) FormClass(org.activityinfo.model.form.FormClass) XFormInstanceImpl(org.activityinfo.server.endpoint.odk.xform.XFormInstanceImpl) XFormInstance(org.activityinfo.server.endpoint.odk.xform.XFormInstance) FormInstance(org.activityinfo.model.form.FormInstance) FormField(org.activityinfo.model.form.FormField) KeyGenerator(org.activityinfo.model.legacy.KeyGenerator) XFormInstance(org.activityinfo.server.endpoint.odk.xform.XFormInstance)

Example 4 with AttachmentValue

use of org.activityinfo.model.type.attachment.AttachmentValue in project activityinfo by bedatadriven.

the class Updater method checkBlobPermissions.

/**
 * Verifies that the user has permission to associate the given blob with this record.
 *
 * <p>Updating blob-valued fields is done by the user in two steps. First, the user uploads a file and
 * receives a unique id for the blob. Then, the user updates a record's field with the blob's unique id. </p>
 *
 * <p>Once the blob is associated with the record, then any user with permission to view the record is extended
 * permission to view the blob. This opens an avenue of attack where by an attacker with seeks to obtain access
 * to a blob with some id by assigning it to an unrelated record to which they have access.</p>
 *
 * <p>For this reason, only users who originally uploaded the blob may assign the blob to a record's field value.</p>
 */
private void checkBlobPermissions(FormField field, Optional<FormRecord> existingResource, AttachmentValue updatedValue) {
    AttachmentType fieldType = (AttachmentType) field.getType();
    // Identity the blob ids that are already associated with this record
    Set<String> existingBlobIds = new HashSet<>();
    if (existingResource.isPresent()) {
        JsonValue existingFieldValue = existingResource.get().getFields().get(field.getId().asString());
        if (!existingFieldValue.isJsonNull()) {
            AttachmentValue existingValue = fieldType.parseJsonValue(existingFieldValue);
            for (Attachment attachment : existingValue.getValues()) {
                existingBlobIds.add(attachment.getBlobId());
            }
        }
    }
    // Assert that the user owns the blob they are associating with the record
    for (Attachment attachment : updatedValue.getValues()) {
        if (!existingBlobIds.contains(attachment.getBlobId())) {
            if (!blobAuthorizer.isOwner(userId, attachment.getBlobId())) {
                throw new InvalidUpdateException(String.format("User %d does not own blob %s", userId, attachment.getBlobId()));
            }
        }
    }
}
Also used : AttachmentValue(org.activityinfo.model.type.attachment.AttachmentValue) AttachmentType(org.activityinfo.model.type.attachment.AttachmentType) JsonValue(org.activityinfo.json.JsonValue) Attachment(org.activityinfo.model.type.attachment.Attachment)

Aggregations

AttachmentValue (org.activityinfo.model.type.attachment.AttachmentValue)4 FormClass (org.activityinfo.model.form.FormClass)2 FormInstance (org.activityinfo.model.form.FormInstance)2 KeyGenerator (org.activityinfo.model.legacy.KeyGenerator)2 ResourceId (org.activityinfo.model.resource.ResourceId)2 Attachment (org.activityinfo.model.type.attachment.Attachment)2 Optional (com.google.common.base.Optional)1 JsonValue (org.activityinfo.json.JsonValue)1 AuthenticatedUser (org.activityinfo.legacy.shared.AuthenticatedUser)1 FormField (org.activityinfo.model.form.FormField)1 AttachmentType (org.activityinfo.model.type.attachment.AttachmentType)1 LocalDate (org.activityinfo.model.type.time.LocalDate)1 OnDataSet (org.activityinfo.server.database.OnDataSet)1 XFormInstance (org.activityinfo.server.endpoint.odk.xform.XFormInstance)1 XFormInstanceImpl (org.activityinfo.server.endpoint.odk.xform.XFormInstanceImpl)1 Test (org.junit.Test)1 Element (org.w3c.dom.Element)1