Search in sources :

Example 1 with JobAuthorization

use of org.dataportabilityproject.spi.cloud.types.JobAuthorization in project data-transfer-project by google.

the class JobPollingServiceTest method pollingLifeCycle.

// TODO(data-portability/issues/43): Make this an integration test which uses both the API and
// worker, rather than simulating API calls, in case this test ever diverges from what the API
// actually does.
@Test
public void pollingLifeCycle() throws Exception {
    when(asymmetricKeyGenerator.generate()).thenReturn(TEST_KEY_PAIR);
    // Initial state
    assertThat(JobMetadata.isInitialized()).isFalse();
    // Run once with no data in the database
    jobPollingService.runOneIteration();
    assertThat(JobMetadata.isInitialized()).isFalse();
    PortabilityJob job = store.findJob(TEST_ID);
    // No existing ready job
    assertThat(job).isNull();
    // API inserts an job in initial authorization state
    job = PortabilityJob.builder().setTransferDataType("photo").setExportService("DummyExportService").setImportService("DummyImportService").setAndValidateJobAuthorization(JobAuthorization.builder().setState(State.INITIAL).setSessionSecretKey("fooBar").build()).build();
    store.createJob(TEST_ID, job);
    // Verify initial authorization state
    job = store.findJob(TEST_ID);
    assertThat(job.jobAuthorization().state()).isEqualTo(State.INITIAL);
    // no auth data should exist yet
    assertThat(job.jobAuthorization().encryptedExportAuthData()).isNull();
    assertThat(job.jobAuthorization().encryptedImportAuthData()).isNull();
    // API atomically updates job to from 'initial' to 'creds available'
    job = job.toBuilder().setAndValidateJobAuthorization(job.jobAuthorization().toBuilder().setState(State.CREDS_AVAILABLE).build()).build();
    store.updateJob(TEST_ID, job);
    // Verify 'creds available' state
    job = store.findJob(TEST_ID);
    assertThat(job.jobAuthorization().state()).isEqualTo(State.CREDS_AVAILABLE);
    // no auth data should exist yet
    assertThat(job.jobAuthorization().encryptedExportAuthData()).isNull();
    assertThat(job.jobAuthorization().encryptedImportAuthData()).isNull();
    // Worker initiates the JobPollingService
    jobPollingService.runOneIteration();
    assertThat(JobMetadata.isInitialized()).isTrue();
    assertThat(JobMetadata.getJobId()).isEqualTo(TEST_ID);
    // Verify assigned without auth data state
    job = store.findJob(TEST_ID);
    assertThat(job.jobAuthorization().state()).isEqualTo(JobAuthorization.State.CREDS_ENCRYPTION_KEY_GENERATED);
    assertThat(job.jobAuthorization().authPublicKey()).isNotEmpty();
    // Client encrypts data and updates the job
    job = job.toBuilder().setAndValidateJobAuthorization(job.jobAuthorization().toBuilder().setEncryptedExportAuthData("dummy export data").setEncryptedImportAuthData("dummy import data").setState(State.CREDS_ENCRYPTED).build()).build();
    store.updateJob(TEST_ID, job);
    // Run another iteration of the polling service
    // Worker should pick up encrypted data and update job
    jobPollingService.runOneIteration();
    job = store.findJob(TEST_ID);
    JobAuthorization jobAuthorization = job.jobAuthorization();
    assertThat(jobAuthorization.state()).isEqualTo(JobAuthorization.State.CREDS_ENCRYPTED);
    assertThat(jobAuthorization.encryptedExportAuthData()).isNotEmpty();
    assertThat(jobAuthorization.encryptedImportAuthData()).isNotEmpty();
    store.remove(TEST_ID);
}
Also used : PortabilityJob(org.dataportabilityproject.spi.cloud.types.PortabilityJob) JobAuthorization(org.dataportabilityproject.spi.cloud.types.JobAuthorization) Test(org.junit.Test)

Example 2 with JobAuthorization

use of org.dataportabilityproject.spi.cloud.types.JobAuthorization in project data-transfer-project by google.

the class SetupHandler method handleImportSetup.

private DataTransferResponse handleImportSetup(Headers headers, PortabilityJob job, UUID jobId) throws IOException {
    String exportAuthCookie = ReferenceApiUtils.getCookie(headers, JsonKeys.EXPORT_AUTH_DATA_COOKIE_KEY);
    Preconditions.checkArgument(!Strings.isNullOrEmpty(exportAuthCookie), "Export auth cookie required");
    // Initial auth flow url
    AuthDataGenerator generator = registry.getAuthDataGenerator(job.importService(), job.transferDataType(), AuthMode.IMPORT);
    Preconditions.checkNotNull(generator, "Generator not found for type: %s, service: %s", job.transferDataType(), job.importService());
    String encodedJobId = ReferenceApiUtils.encodeJobId(jobId);
    AuthFlowConfiguration authFlowConfiguration = generator.generateConfiguration(baseApiUrl, encodedJobId);
    Preconditions.checkNotNull(authFlowConfiguration, "AuthFlowConfiguration not found for type: %s, service: %s", job.transferDataType(), job.importService());
    // If present, store initial auth data for export services, e.g. used for oauth1
    if (authFlowConfiguration.getInitialAuthData() != null) {
        // Retrieve and parse the session key from the job
        String sessionKey = job.jobAuthorization().sessionSecretKey();
        SecretKey key = symmetricKeyGenerator.parse(BaseEncoding.base64Url().decode(sessionKey));
        // Ensure intial auth data for import has not already been set
        Preconditions.checkState(Strings.isNullOrEmpty(job.jobAuthorization().encryptedInitialImportAuthData()));
        // Serialize and encrypt the initial auth data
        String serialized = objectMapper.writeValueAsString(authFlowConfiguration.getInitialAuthData());
        String encryptedInitialAuthData = EncrypterFactory.create(key).encrypt(serialized);
        // Add the serialized and encrypted initial auth data to the job authorization
        JobAuthorization updatedJobAuthorization = job.jobAuthorization().toBuilder().setEncryptedInitialImportAuthData(encryptedInitialAuthData).build();
        // Persist the updated PortabilityJob with the updated JobAuthorization
        PortabilityJob updatedPortabilityJob = job.toBuilder().setAndValidateJobAuthorization(updatedJobAuthorization).build();
        store.updateJob(jobId, updatedPortabilityJob);
    }
    return new DataTransferResponse(job.exportService(), job.importService(), job.transferDataType(), Status.INPROCESS, // Redirect to auth page of import service
    authFlowConfiguration.getUrl());
}
Also used : AuthFlowConfiguration(org.dataportabilityproject.spi.gateway.types.AuthFlowConfiguration) AuthDataGenerator(org.dataportabilityproject.spi.gateway.auth.AuthDataGenerator) JobAuthorization(org.dataportabilityproject.spi.cloud.types.JobAuthorization) PortabilityJob(org.dataportabilityproject.spi.cloud.types.PortabilityJob) SecretKey(javax.crypto.SecretKey) DataTransferResponse(org.dataportabilityproject.types.client.transfer.DataTransferResponse)

Example 3 with JobAuthorization

use of org.dataportabilityproject.spi.cloud.types.JobAuthorization in project data-transfer-project by google.

the class DataTransferHandler method handle.

/**
 * Services the {@link CreateJobAction} via the {@link HttpExchange}.
 */
@Override
public void handle(HttpExchange exchange) throws IOException {
    Preconditions.checkArgument(ReferenceApiUtils.validateRequest(exchange, HttpMethods.POST, PATH), PATH + " only supports POST.");
    logger.debug("received request: {}", exchange.getRequestURI());
    DataTransferRequest request = objectMapper.readValue(exchange.getRequestBody(), DataTransferRequest.class);
    CreateJobActionRequest actionRequest = new CreateJobActionRequest(request.getSource(), request.getDestination(), request.getTransferDataType());
    CreateJobActionResponse actionResponse = createJobAction.handle(actionRequest);
    DataTransferResponse dataTransferResponse;
    if (actionResponse.getErrorMsg() != null) {
        logger.warn("Error during action: {}", actionResponse.getErrorMsg());
        handleError(exchange, request);
        return;
    }
    // Set new cookie
    String encodedJobId = ReferenceApiUtils.encodeJobId(actionResponse.getId());
    HttpCookie cookie = new HttpCookie(JsonKeys.ID_COOKIE_KEY, encodedJobId);
    exchange.getResponseHeaders().add(HttpHeaders.SET_COOKIE, cookie.toString() + ReferenceApiUtils.COOKIE_ATTRIBUTES);
    // Initial auth flow url
    AuthDataGenerator generator = registry.getAuthDataGenerator(request.getSource(), request.getTransferDataType(), AuthMode.EXPORT);
    Preconditions.checkNotNull(generator, "Generator not found for type: %s, service: %s", request.getTransferDataType(), request.getSource());
    AuthFlowConfiguration authFlowConfiguration = generator.generateConfiguration(baseApiUrl, encodedJobId);
    Preconditions.checkNotNull(authFlowConfiguration, "AuthFlowConfiguration not found for type: %s, service: %s", request.getTransferDataType(), request.getSource());
    PortabilityJob job = store.findJob(actionResponse.getId());
    logger.debug("Found job: {} in DTH", job);
    // If present, store initial auth data for export services, e.g. used for oauth1
    if (authFlowConfiguration.getInitialAuthData() != null) {
        // Retrieve and parse the session key from the job
        String sessionKey = job.jobAuthorization().sessionSecretKey();
        SecretKey key = symmetricKeyGenerator.parse(BaseEncoding.base64Url().decode(sessionKey));
        // Ensure intial auth data for export has not already been set
        Preconditions.checkState(Strings.isNullOrEmpty(job.jobAuthorization().encryptedInitialExportAuthData()));
        // Serialize and encrypt the initial auth data
        String serialized = objectMapper.writeValueAsString(authFlowConfiguration.getInitialAuthData());
        String encryptedInitialAuthData = EncrypterFactory.create(key).encrypt(serialized);
        // Add the serialized and encrypted initial auth data to the job authorization
        JobAuthorization updatedJobAuthorization = job.jobAuthorization().toBuilder().setEncryptedInitialExportAuthData(encryptedInitialAuthData).build();
        // Persist the updated PortabilityJob with the updated JobAuthorization
        PortabilityJob updatedPortabilityJob = job.toBuilder().setAndValidateJobAuthorization(updatedJobAuthorization).build();
        store.updateJob(actionResponse.getId(), updatedPortabilityJob);
        logger.debug("Updated job is: {}", updatedPortabilityJob);
        PortabilityJob storejob = store.findJob(actionResponse.getId());
        logger.debug("Job looked up in jobstore is: {} -> {}", actionResponse.getId(), storejob);
    }
    dataTransferResponse = new DataTransferResponse(request.getSource(), request.getDestination(), request.getTransferDataType(), Status.INPROCESS, authFlowConfiguration.getUrl());
    logger.debug("redirecting to: {}", authFlowConfiguration.getUrl());
    // Mark the response as type Json and send
    exchange.getResponseHeaders().set(CONTENT_TYPE, "application/json; charset=" + StandardCharsets.UTF_8.name());
    exchange.sendResponseHeaders(200, 0);
    objectMapper.writeValue(exchange.getResponseBody(), dataTransferResponse);
}
Also used : AuthFlowConfiguration(org.dataportabilityproject.spi.gateway.types.AuthFlowConfiguration) AuthDataGenerator(org.dataportabilityproject.spi.gateway.auth.AuthDataGenerator) PortabilityJob(org.dataportabilityproject.spi.cloud.types.PortabilityJob) JobAuthorization(org.dataportabilityproject.spi.cloud.types.JobAuthorization) SecretKey(javax.crypto.SecretKey) DataTransferRequest(org.dataportabilityproject.types.client.transfer.DataTransferRequest) DataTransferResponse(org.dataportabilityproject.types.client.transfer.DataTransferResponse) HttpCookie(java.net.HttpCookie) CreateJobActionRequest(org.dataportabilityproject.gateway.action.createjob.CreateJobActionRequest) CreateJobActionResponse(org.dataportabilityproject.gateway.action.createjob.CreateJobActionResponse)

Example 4 with JobAuthorization

use of org.dataportabilityproject.spi.cloud.types.JobAuthorization in project data-transfer-project by google.

the class StartJobAction method updateStateToCredsAvailable.

/**
 * Update the job to state to {@code State.CREDS_AVAILABLE} in the store. This indicates to the
 * pool of workers that this job is available for processing.
 */
private void updateStateToCredsAvailable(UUID jobId) {
    PortabilityJob job = store.findJob(jobId);
    validateJob(job);
    // Set update job auth data
    JobAuthorization jobAuthorization = job.jobAuthorization().toBuilder().setState(State.CREDS_AVAILABLE).build();
    job = job.toBuilder().setAndValidateJobAuthorization(jobAuthorization).build();
    try {
        store.updateJob(jobId, job);
        logger.debug("Updated job {} to CREDS_AVAILABLE", jobId);
    } catch (IOException e) {
        throw new RuntimeException("Unable to update job", e);
    }
}
Also used : PortabilityJob(org.dataportabilityproject.spi.cloud.types.PortabilityJob) JobAuthorization(org.dataportabilityproject.spi.cloud.types.JobAuthorization) IOException(java.io.IOException)

Example 5 with JobAuthorization

use of org.dataportabilityproject.spi.cloud.types.JobAuthorization in project data-transfer-project by google.

the class StartJobAction method encryptAndUpdateJobWithCredentials.

/**
 * Encrypt the export and import credentials with a new {@link SecretKey} and {@link PublicKey}
 * assigned to this job then update the data store to {@code State.CREDS_ENCRYPTED} state.
 */
private void encryptAndUpdateJobWithCredentials(UUID jobId, PortabilityJob job, String encryptedExportAuthCredential, String encryptedImportAuthCredential) {
    // Step 1 - Generate authSecretKey, a new SecretKey which must not be persisted as is.
    SecretKey authSecretKey = symmetricKeyGenerator.generate();
    // Step 2 - Encrypt the auth data with authSecretKey
    Encrypter secretKeyEncrypter = EncrypterFactory.create(authSecretKey);
    String doublyEncryptedExportAuthData = secretKeyEncrypter.encrypt(encryptedExportAuthCredential);
    String doublyEncryptedImportAuthData = secretKeyEncrypter.encrypt(encryptedImportAuthCredential);
    // Step 3 - Encrypt the authSecretKey itself with the authPublickey
    PublicKey authPublicKey = asymmetricKeyGenerator.parse(BaseEncoding.base64Url().decode(job.jobAuthorization().authPublicKey()));
    Encrypter asymmetricEncrypter = EncrypterFactory.create(authPublicKey);
    String encryptedAuthSecretKey = asymmetricEncrypter.encrypt(BaseEncoding.base64Url().encode(authSecretKey.getEncoded()));
    // Populate job with encrypted auth data
    JobAuthorization updatedJobAuthorization = job.jobAuthorization().toBuilder().setEncryptedExportAuthData(doublyEncryptedExportAuthData).setEncryptedImportAuthData(doublyEncryptedImportAuthData).setAuthSecretKey(encryptedAuthSecretKey).setState(JobAuthorization.State.CREDS_ENCRYPTED).build();
    job = job.toBuilder().setAndValidateJobAuthorization(updatedJobAuthorization).build();
    logger.debug("Updating job {} from CREDS_ENCRYPTION_KEY_GENERATED to CREDS_ENCRYPTED", jobId);
    try {
        store.updateJob(jobId, job);
        logger.debug("Updated job {} to CREDS_ENCRYPTED", jobId);
    } catch (IOException e) {
        throw new RuntimeException("Unable to update job", e);
    }
}
Also used : Encrypter(org.dataportabilityproject.security.Encrypter) JobAuthorization(org.dataportabilityproject.spi.cloud.types.JobAuthorization) SecretKey(javax.crypto.SecretKey) PublicKey(java.security.PublicKey) IOException(java.io.IOException)

Aggregations

JobAuthorization (org.dataportabilityproject.spi.cloud.types.JobAuthorization)8 PortabilityJob (org.dataportabilityproject.spi.cloud.types.PortabilityJob)6 SecretKey (javax.crypto.SecretKey)4 IOException (java.io.IOException)3 UUID (java.util.UUID)2 AuthDataGenerator (org.dataportabilityproject.spi.gateway.auth.AuthDataGenerator)2 AuthFlowConfiguration (org.dataportabilityproject.spi.gateway.types.AuthFlowConfiguration)2 DataTransferResponse (org.dataportabilityproject.types.client.transfer.DataTransferResponse)2 HttpCookie (java.net.HttpCookie)1 PublicKey (java.security.PublicKey)1 CreateJobActionRequest (org.dataportabilityproject.gateway.action.createjob.CreateJobActionRequest)1 CreateJobActionResponse (org.dataportabilityproject.gateway.action.createjob.CreateJobActionResponse)1 Decrypter (org.dataportabilityproject.security.Decrypter)1 Encrypter (org.dataportabilityproject.security.Encrypter)1 DataTransferRequest (org.dataportabilityproject.types.client.transfer.DataTransferRequest)1 AuthData (org.dataportabilityproject.types.transfer.auth.AuthData)1 Test (org.junit.Test)1