void doPost(final HttpServletRequest req, final HttpServletResponse resp) {
    try {
      // Parse out the required API versions.
      final AcceptAPIVersion acceptVersion = parseAcceptAPIVersion(req);

      // Prepare response.
      prepareResponse(req, resp);

      // Validate request.
      preprocessRequest(req);
      rejectIfNoneMatch(req);
      rejectIfMatch(req);

      final Map<String, String[]> parameters = req.getParameterMap();
      final String action = asSingleValue(PARAM_ACTION, getParameter(req, PARAM_ACTION));
      if (action.equalsIgnoreCase(ACTION_ID_CREATE)) {
        final JsonValue content = getJsonContent(req);
        final CreateRequest request = Requests.newCreateRequest(getResourceName(req), content);
        for (final Map.Entry<String, String[]> p : parameters.entrySet()) {
          final String name = p.getKey();
          final String[] values = p.getValue();
          if (parseCommonParameter(name, values, request)) {
            continue;
          } else if (name.equalsIgnoreCase(PARAM_ACTION)) {
            // Ignore - already handled.
          } else if (HttpUtils.isMultiPartRequest(req.getContentType())) {
            // Ignore - multipart content adds form parts to the parameter set
          } else {
            request.setAdditionalParameter(name, asSingleValue(name, values));
          }
        }
        doRequest(req, resp, acceptVersion, request);
      } else {
        // Action request.
        final JsonValue content = getJsonActionContent(req);
        final ActionRequest request =
            Requests.newActionRequest(getResourceName(req), action).setContent(content);
        for (final Map.Entry<String, String[]> p : parameters.entrySet()) {
          final String name = p.getKey();
          final String[] values = p.getValue();
          if (parseCommonParameter(name, values, request)) {
            continue;
          } else if (name.equalsIgnoreCase(PARAM_ACTION)) {
            // Ignore - already handled.
          } else if (HttpUtils.isMultiPartRequest(req.getContentType())) {
            // Ignore - multipart content adds form parts to the parameter set
          } else {
            request.setAdditionalParameter(name, asSingleValue(name, values));
          }
        }
        doRequest(req, resp, acceptVersion, request);
      }
    } catch (final Exception e) {
      fail(req, resp, e);
    }
  }
  void doDelete(final HttpServletRequest req, final HttpServletResponse resp) {
    try {
      // Parse out the required API versions.
      final AcceptAPIVersion acceptVersion = parseAcceptAPIVersion(req);

      // Prepare response.
      prepareResponse(req, resp);

      // Validate request.
      preprocessRequest(req);
      rejectIfNoneMatch(req);

      final Map<String, String[]> parameters = req.getParameterMap();
      final DeleteRequest request =
          Requests.newDeleteRequest(getResourceName(req)).setRevision(getIfMatch(req));
      for (final Map.Entry<String, String[]> p : parameters.entrySet()) {
        final String name = p.getKey();
        final String[] values = p.getValue();
        if (parseCommonParameter(name, values, request)) {
          continue;
        } else {
          request.setAdditionalParameter(name, asSingleValue(name, values));
        }
      }
      doRequest(req, resp, acceptVersion, request);
    } catch (final Exception e) {
      fail(req, resp, e);
    }
  }
  /**
   * Returns <code>true</code> if a persisted <code>Dictionary</code> exists for the given <code>pid
   * </code>.
   *
   * @param pid The identifier for the dictionary to test.
   */
  public boolean exists(String pid) {
    logger.debug("Config exists call for {}", pid);

    boolean exists = false;

    if (isReady(0) && requireRepository) {
      String id = pidToId(pid);
      try {
        ReadRequest readRequest = Requests.newReadRequest(id);
        Resource existing = repo.read(readRequest);
        exists = (existing != null);
      } catch (NotFoundException ex) {
        exists = false;
      } catch (ResourceException ex) {
        throw new RuntimeException(
            "Failed to check if configuration exists in repository: " + ex.getMessage(), ex);
      }
    }
    if (!exists) {
      exists = tempStore.containsKey(pid);
      if (exists) {
        logger.debug("Entry exists in temporary store for '{}'", pid);
      }
    } else {
      logger.debug("Entry exists for '{}'", pid);
    }

    if (!exists) {
      logger.debug("Entry does not exist for '{}'", pid);
    }
    return exists;
  }
  /**
   * Returns the <code>Dictionary</code> for the given <code>pid</code>.
   *
   * @param pid The identifier for the dictionary to load.
   * @return The dictionary for the identifier. This must not be <code>null</code> but may be empty.
   * @throws IOException If an error occurrs loading the dictionary. An <code>IOException</code>
   *     must also be thrown if no dictionary exists for the given identifier.
   */
  public Dictionary load(String pid) throws IOException {
    logger.debug("Config load call for {}", pid);
    Dictionary result = null;

    try {
      if (isReady(0) && requireRepository) {
        String id = pidToId(pid);
        ReadRequest readRequest = Requests.newReadRequest(id);
        Resource existing = repo.read(readRequest);
        Map<String, Object> existingConfig = existing.getContent().asMap();
        Object configMap = existingConfig.get(JSONEnhancedConfig.JSON_CONFIG_PROPERTY);
        String configString = serializeConfig(configMap);
        existingConfig.put(JSONEnhancedConfig.JSON_CONFIG_PROPERTY, configString);
        logger.debug("Config loaded {} {}", pid, existing);
        result = mapToDict(existingConfig);
      } else if (!requireRepository) {
        result = tempStore.get(pid);
        if (result == null) {
          throw new IOException("No entry for " + pid + " exists.");
        }

        logger.debug("Config loaded from temporary store {} {}", pid, result);
      }
    } catch (NotFoundException ex) {
      result = tempStore.get(pid);
      if (result == null) {
        throw new IOException("No entry for " + pid + " exists.");
      }

      logger.debug("Config loaded from temporary store {} {}", pid, result);
    } catch (ResourceException ex) {
      throw new IOException("Failed to load configuration in repository: " + ex.getMessage(), ex);
    }
    return result;
  }
  /**
   * Creates the underlying backend policies.
   *
   * <p>NOTE: if the creation of the underlying policies fails, any successfully created underlying
   * policies will be attempted to be deleted but if the deletion fails, then the underlying
   * policies may be in an inconsistent state.
   *
   * @param context The request context.
   * @param policies The underlying policies to create.
   * @return A promise containing the list of created underlying policies or a {@code
   *     ResourceException} if the creation fails.
   */
  public Promise<List<Resource>, ResourceException> createPolicies(
      ServerContext context, Set<JsonValue> policies) {

    final List<String> policyIds = new ArrayList<String>();
    List<Promise<Resource, ResourceException>> promises =
        new ArrayList<Promise<Resource, ResourceException>>();
    for (JsonValue policy : policies) {
      promises.add(
          policyResource
              .handleCreate(context, Requests.newCreateRequest("", policy))
              .thenOnResult(
                  new ResultHandler<Resource>() {
                    @Override
                    public void handleResult(Resource result) {
                      // Save ids of created policies, in case a latter policy fails to be created,
                      // so we can roll back.
                      policyIds.add(result.getId());
                    }
                  }));
    }
    return Promises.when(promises)
        .thenAsync(
            new AsyncFunction<List<Resource>, List<Resource>, ResourceException>() {
              @Override
              public Promise<List<Resource>, ResourceException> apply(List<Resource> value) {
                return Promises.newResultPromise(value);
              }
            },
            new UmaPolicyCreateFailureHandler(context, policyIds));
  }
  @Test
  public void crestActionBlowupIsAllowed() throws SSOException, DelegationException {
    // Given...
    final Set<String> actions = new HashSet<>(Arrays.asList("MODIFY"));
    final DelegationPermission permission =
        new DelegationPermission(
            "/abc", "rest", "1.0", "policies", "destroy", actions, EXTENSIONS, DUMB_FUNC);
    given(factory.newInstance("/abc", "rest", "1.0", "policies", "destroy", actions, EXTENSIONS))
        .willReturn(permission);

    given(subjectContext.getCallerSSOToken()).willReturn(token);
    given(evaluator.isAllowed(eq(token), eq(permission), eq(ENVIRONMENT))).willReturn(true);

    JsonValue jsonValue = json(object(field("someKey", "someValue")));
    Promise<ActionResponse, ResourceException> promise =
        Promises.newResultPromise(Responses.newActionResponse(jsonValue));
    given(provider.actionCollection(isA(Context.class), isA(ActionRequest.class)))
        .willReturn(promise);

    // When...
    final FilterChain chain = AuthorizationFilters.createAuthorizationFilter(provider, module);
    final Router router = new Router();
    router.addRoute(RoutingMode.STARTS_WITH, Router.uriTemplate("/policies"), chain);

    final RealmContext context = new RealmContext(subjectContext);
    context.setSubRealm("abc", "abc");
    final ActionRequest request = Requests.newActionRequest("/policies", "blowup");
    Promise<ActionResponse, ResourceException> result = router.handleAction(context, request);

    // Then...
    assertThat(result).succeeded().withContent().stringAt("someKey").isEqualTo("someValue");
  }
  /**
   * Queries relationships, returning the relationship associated with this providers resource path
   * and the specified relationship field.
   *
   * @param context The current context
   * @param managedObjectId The id of the managed object to find relationships associated with
   * @return
   */
  private Promise<ResourceResponse, ResourceException> queryRelationship(
      final Context context, final String managedObjectId) {
    try {
      final QueryRequest queryRequest = Requests.newQueryRequest(REPO_RESOURCE_PATH);
      final List<ResourceResponse> relationships = new ArrayList<>();

      queryRequest.setQueryFilter(
          QueryFilter.and(
              QueryFilter.equalTo(
                  new JsonPointer(isReverse ? REPO_FIELD_SECOND_ID : REPO_FIELD_FIRST_ID),
                  resourcePath.child(managedObjectId)),
              QueryFilter.equalTo(new JsonPointer(REPO_FIELD_FIRST_PROPERTY_NAME), propertyName)));

      connectionFactory.getConnection().query(context, queryRequest, relationships);

      if (relationships.isEmpty()) {
        return new NotFoundException().asPromise();
      } else {
        // TODO OPENIDM-4094 - check size and throw illegal state if more than one?
        return newResultPromise(FORMAT_RESPONSE.apply(relationships.get(0)));
      }
    } catch (ResourceException e) {
      return e.asPromise();
    }
  }
  @Test
  public void crestRequestNotAllowed() throws SSOException, DelegationException {
    // Given...
    final Set<String> actions = new HashSet<>(Arrays.asList("MODIFY"));
    final DelegationPermission permission =
        new DelegationPermission(
            "/abc", "rest", "1.0", "policies", "modify", actions, EXTENSIONS, DUMB_FUNC);
    given(factory.newInstance("/abc", "rest", "1.0", "policies", "modify", actions, EXTENSIONS))
        .willReturn(permission);

    given(subjectContext.getCallerSSOToken()).willReturn(token);
    given(evaluator.isAllowed(eq(token), eq(permission), eq(ENVIRONMENT))).willReturn(false);

    // When...
    final FilterChain chain = AuthorizationFilters.createAuthorizationFilter(provider, module);
    final Router router = new Router();
    router.addRoute(RoutingMode.STARTS_WITH, Router.uriTemplate("/policies"), chain);

    final RealmContext context = new RealmContext(subjectContext);
    context.setSubRealm("abc", "abc");
    final CreateRequest request =
        Requests.newCreateRequest("/policies", JsonValue.json(new Object()));
    Promise<ResourceResponse, ResourceException> promise = router.handleCreate(context, request);

    // Then...
    assertThat(promise).failedWithException().isInstanceOf(ForbiddenException.class);
  }
 /**
  * Deletes the underlying backend policies.
  *
  * <p>NOTE: if the deletion of the underlying policies fails, the underlying policies may be in an
  * inconsistent state.
  *
  * @param context The request context.
  * @param policyIds The list of ids of the underlying backend policies to delete.
  * @return A promise containing the list of underlying policies that were deleted or a {@code
  *     ResourceException} if the policies were failed to be deleted.
  */
 public Promise<List<Resource>, ResourceException> deletePolicies(
     ServerContext context, Collection<String> policyIds) {
   List<Promise<Resource, ResourceException>> promises =
       new ArrayList<Promise<Resource, ResourceException>>();
   for (String policyId : policyIds) {
     promises.add(policyResource.handleDelete(context, Requests.newDeleteRequest(policyId)));
   }
   return Promises.when(promises);
 }
  /**
   * Persist the supplied {@link JsonValue} {@code value} as the new state of this singleton
   * relationship on {@code resourceId}.
   *
   * <p><em>This is currently the only means of creating an instance of this singleton</em>
   *
   * @param context The context of this request
   * @param resourceId Id of the resource relation fields in value are to be memebers of
   * @param value A {@link JsonValue} map of relationship fields and their values
   * @return The persisted instance of {@code value}
   */
  @Override
  public Promise<JsonValue, ResourceException> setRelationshipValueForResource(
      Context context, String resourceId, JsonValue value) {
    if (value.isNotNull()) {
      try {
        final JsonValue id = value.get(FIELD_ID);

        // Update if we got an id, otherwise replace
        if (id != null && id.isNotNull()) {
          final UpdateRequest updateRequest = Requests.newUpdateRequest("", value);
          updateRequest.setAdditionalParameter(PARAM_FIRST_ID, resourceId);
          return updateInstance(context, value.get(FIELD_ID).asString(), updateRequest)
              .then(
                  new Function<ResourceResponse, JsonValue, ResourceException>() {
                    @Override
                    public JsonValue apply(ResourceResponse resourceResponse)
                        throws ResourceException {
                      return resourceResponse.getContent();
                    }
                  });
        } else { // no id, replace current instance
          clear(context, resourceId);

          final CreateRequest createRequest = Requests.newCreateRequest("", value);
          createRequest.setAdditionalParameter(PARAM_FIRST_ID, resourceId);
          return createInstance(context, createRequest)
              .then(
                  new Function<ResourceResponse, JsonValue, ResourceException>() {
                    @Override
                    public JsonValue apply(ResourceResponse resourceResponse)
                        throws ResourceException {
                      return resourceResponse.getContent();
                    }
                  });
        }
      } catch (ResourceException e) {
        return e.asPromise();
      }

    } else {
      clear(context, resourceId);
      return newResultPromise(json(null));
    }
  }
 /**
  * Updates the underlying backend policies.
  *
  * <p>NOTE: if the update of the underlying policies fails, the underlying policies may be in an
  * inconsistent state.
  *
  * @param context The request context.
  * @param policies The updated underlying policies to update.
  * @return A promise containing the list of updated underlying policies or a {@code
  *     ResourceException} if the update failed.
  */
 public Promise<List<Resource>, ResourceException> updatePolicies(
     ServerContext context, Set<JsonValue> policies) {
   List<Promise<Resource, ResourceException>> promises =
       new ArrayList<Promise<Resource, ResourceException>>();
   for (JsonValue policy : policies) {
     String policyName = policy.get("name").asString();
     promises.add(
         policyResource.handleUpdate(context, Requests.newUpdateRequest(policyName, policy)));
   }
   return Promises.when(promises);
 }
 @Override
 public Promise<ActionResponse, ResourceException> handleAction(
     final Context context, final ActionRequest request) {
   try {
     Map<String, String> params = request.getAdditionalParameters();
     switch (request.getActionAsEnum(Action.class)) {
       case updateDbCredentials:
         String newUser = params.get("user");
         String newPassword = params.get("password");
         if (newUser == null || newPassword == null) {
           return adapt(new BadRequestException("Expecting 'user' and 'password' parameters"))
               .asPromise();
         }
         synchronized (dbLock) {
           DBHelper.updateDbCredentials(dbURL, user, password, newUser, newPassword);
           JsonValue config =
               connectionFactory
                   .getConnection()
                   .read(context, Requests.newReadRequest("config", PID))
                   .getContent();
           config.put("user", newUser);
           config.put("password", newPassword);
           UpdateRequest updateRequest = Requests.newUpdateRequest("config/" + PID, config);
           connectionFactory.getConnection().update(context, updateRequest);
           return newActionResponse(new JsonValue(params)).asPromise();
         }
       case command:
         return newActionResponse(new JsonValue(command(request))).asPromise();
       default:
         return adapt(new BadRequestException("Unknown action: " + request.getAction()))
             .asPromise();
     }
   } catch (IllegalArgumentException e) {
     return adapt(new BadRequestException("Unknown action: " + request.getAction())).asPromise();
   } catch (ResourceException e) {
     return e.asPromise();
   }
 }
  @Test
  public void testReadSchedule() throws Exception {
    // given
    final ReadRequest readRequest = Requests.newReadRequest("test1");

    // when
    Promise<ResourceResponse, ResourceException> promise =
        schedulerService.handleRead(new RootContext(), readRequest);

    // then
    AssertJPromiseAssert.assertThat(promise).isNotNull().succeeded();
    ResourceResponse resourceResponse = promise.getOrThrow();
    assertThat(resourceResponse.getContent().asMap()).isEqualTo(testScheduleConfig.asMap());
  }
  @Test
  public void crestActionNoMappingFails() throws SSOException, DelegationException {
    // When...
    final FilterChain chain = AuthorizationFilters.createAuthorizationFilter(provider, module);
    final Router router = new Router();
    router.addRoute(RoutingMode.STARTS_WITH, Router.uriTemplate("/policies"), chain);

    final Context context = new RealmContext(subjectContext);
    final ActionRequest request = Requests.newActionRequest("/policies", "unknownAction");
    Promise<ActionResponse, ResourceException> promise = router.handleAction(context, request);

    // Then...
    assertThat(promise).failedWithException().isInstanceOf(ForbiddenException.class);
  }
  /**
   * Removes the <code>Dictionary</code> for the given <code>pid</code>. If such a dictionary does
   * not exist, this method has no effect.
   *
   * @param pid The identifier of the dictionary to delet.
   * @throws IOException If an error occurrs deleting the dictionary. This exception must not be
   *     thrown if no dictionary with the given identifier exists.
   */
  public void delete(String pid) throws IOException {
    logger.debug("delete call for {}", pid);
    Object removed = tempStore.remove(pid);
    if (removed != null) {
      logger.debug("Deleted {} from temporary store", pid);
    }
    try {
      if (isReady(0) && requireRepository) {
        String id = pidToId(pid);
        boolean retry;
        String rev = null;
        do {
          retry = false;
          try {

            ReadRequest readRequest = Requests.newReadRequest(id);
            Map<String, Object> existing = repo.read(readRequest).getContent().asMap();
            if (existing != null) {
              rev = (String) existing.get("_rev");
              DeleteRequest r = Requests.newDeleteRequest(id);
              r.setRevision(rev);
              repo.delete(r);
              logger.debug("Deleted {}", pid);
            }
          } catch (PreconditionFailedException ex) {
            logger.debug("Concurrent change during delete, retrying {} {}", pid, rev);
            retry = true;
          } catch (NotFoundException ex) {
            // If it doesn't exists (anymore) that's fine
          }
        } while (retry);
      }
    } catch (ResourceException ex) {
      throw new IOException(
          "Failed to delete configuration + " + pid + " in repository: " + ex.getMessage(), ex);
    }
  }
  @Test
  public void testListCurrentlyExecutingJobsAction() throws Exception {
    // given
    final ActionRequest readRequest =
        Requests.newActionRequest("", SchedulerAction.listCurrentlyExecutingJobs.toString());

    // when
    Promise<ActionResponse, ResourceException> promise =
        schedulerService.handleAction(new RootContext(), readRequest);

    // then
    AssertJPromiseAssert.assertThat(promise).isNotNull().succeeded();
    ActionResponse resourceResponse = promise.getOrThrow();
    assertThat(resourceResponse.getJsonContent().asList().size()).isEqualTo(0);
  }
  @Test
  public void testResumeJobsAction() throws Exception {
    // given
    final ActionRequest readRequest =
        Requests.newActionRequest("", SchedulerAction.resumeJobs.toString());

    // when
    Promise<ActionResponse, ResourceException> promise =
        schedulerService.handleAction(new RootContext(), readRequest);

    // then
    AssertJPromiseAssert.assertThat(promise).isNotNull().succeeded();
    ActionResponse resourceResponse = promise.getOrThrow();
    assertThat(resourceResponse.getJsonContent().get("success").getObject())
        .isEqualTo(new Boolean(true));
  }
Example #18
0
 /**
  * TODO: Description.
  *
  * @throws SynchronizationException TODO.
  */
 void delete() throws SynchronizationException {
   if (_id != null) { // forgiving delete
     try {
       DeleteRequest r = Requests.newDeleteRequest(linkId(_id));
       r.setRevision(_rev);
       mapping
           .getService()
           .getConnectionFactory()
           .getConnection()
           .delete(mapping.getService().getServerContext(), r);
     } catch (ResourceException ose) {
       LOGGER.warn("Failed to delete link", ose);
       throw new SynchronizationException(ose);
     }
     clear();
   }
 }
  /**
   * Calls buildAuditEvent() and invokes the request to the audit path.
   *
   * @param connectionFactory factory used to make crest call to audit service.
   */
  public final Promise<ResourceResponse, ResourceException> log(
      ConfigAuditState configAuditState,
      Request request,
      Context context,
      ConnectionFactory connectionFactory) {
    try {

      JsonValue before = configAuditState.getBefore();
      JsonValue after = configAuditState.getAfter();

      // Get authenticationId from security context, if it exists.
      String authenticationId =
          (context.containsContext(SecurityContext.class))
              ? context.asContext(SecurityContext.class).getAuthenticationId()
              : null;

      // Build the event utilizing the config builder.
      AuditEvent auditEvent =
          ConfigAuditEventBuilder.configEvent()
              .resourceOperationFromRequest(request)
              .authenticationFromSecurityContext(context)
              .runAs(authenticationId)
              .transactionIdFromRootContext(context)
              .revision(configAuditState.getRevision())
              .timestamp(System.currentTimeMillis())
              .eventName(CONFIG_AUDIT_EVENT_NAME)
              .before(null != before ? before.toString() : "")
              .after(null != after ? after.toString() : "")
              .changedFields(getChangedFields(before, after))
              .toEvent();

      return connectionFactory
          .getConnection()
          .create(context, Requests.newCreateRequest(AUDIT_CONFIG_REST_PATH, auditEvent.getValue()))
          .asPromise();
    } catch (ResourceException e) {
      LOGGER.error("had trouble logging audit event for config changes.", e);
      return e.asPromise();
    } catch (Exception e) {
      LOGGER.error("had trouble logging audit event for config changes.", e);
      return new InternalServerErrorException(e.getMessage(), e).asPromise();
    }
  }
Example #20
0
 /**
  * TODO: Description.
  *
  * @throws SynchronizationException TODO.
  */
 void create() throws SynchronizationException {
   _id = UUID.randomUUID().toString(); // client-assigned identifier
   JsonValue jv = toJsonValue();
   try {
     CreateRequest r = Requests.newCreateRequest(linkId(null), _id, jv);
     Resource resource =
         mapping
             .getService()
             .getConnectionFactory()
             .getConnection()
             .create(mapping.getService().getServerContext(), r);
     this._id = resource.getId();
     this._rev = resource.getRevision();
     this.initialized = true;
   } catch (ResourceException ose) {
     LOGGER.debug("Failed to create link", ose);
     throw new SynchronizationException(ose);
   }
 }
Example #21
0
  @Test
  public void testResource() throws Exception {
    ScriptName scriptName = new ScriptName("resource", getLanguageName());
    ScriptEntry scriptEntry = getScriptRegistry().takeScript(scriptName);
    Assert.assertNotNull(scriptEntry);

    Script script = scriptEntry.getScript(new RootContext());
    // Set RequestLevel Scope
    script.put("ketto", 2);
    script.putSafe("callback", mock(Function.class));

    JsonValue createContent = new JsonValue(new LinkedHashMap<String, Object>());
    createContent.put("externalId", "701984");
    createContent.put("userName", "*****@*****.**");
    createContent.put(
        "assignedDashboard", Arrays.asList("Salesforce", "Google", "ConstantContact"));
    createContent.put("displayName", "Babs Jensen");
    createContent.put("nickName", "Babs");

    JsonValue updateContent = createContent.copy();
    updateContent.put("_id", UUID.randomUUID().toString());
    updateContent.put("profileUrl", "https://login.example.com/bjensen");

    final Context context =
        new ApiInfoContext(
            new SecurityContext(new RootContext(), "*****@*****.**", null), "", "");
    script.put("context", context);

    CreateRequest createRequest = Requests.newCreateRequest("/Users", "701984", createContent);
    script.put("createRequest", createRequest);
    ReadRequest readRequest = Requests.newReadRequest("/Users/701984");
    script.put("readRequest", readRequest);
    UpdateRequest updateRequest = Requests.newUpdateRequest("/Users/701984", updateContent);
    script.put("updateRequest", updateRequest);
    PatchRequest patchRequest =
        Requests.newPatchRequest("/Users/701984", PatchOperation.replace("userName", "ddoe"));
    script.put("patchRequest", patchRequest);
    QueryRequest queryRequest = Requests.newQueryRequest("/Users/");
    script.put("queryRequest", queryRequest);
    DeleteRequest deleteRequest = Requests.newDeleteRequest("/Users/701984");
    script.put("deleteRequest", deleteRequest);
    ActionRequest actionRequest = Requests.newActionRequest("/Users", "clear");
    script.put("actionRequest", actionRequest);
    script.eval();
  }
Example #22
0
 /**
  * Update a link.
  *
  * @throws SynchronizationException if updating link fails
  */
 void update() throws SynchronizationException {
   if (_id == null) {
     throw new SynchronizationException("Attempt to update non-existent link");
   }
   JsonValue jv = toJsonValue();
   try {
     UpdateRequest r = Requests.newUpdateRequest(linkId(_id), jv);
     r.setRevision(_rev);
     Resource resource =
         mapping
             .getService()
             .getConnectionFactory()
             .getConnection()
             .update(mapping.getService().getServerContext(), r);
     _rev = resource.getRevision();
   } catch (ResourceException ose) {
     LOGGER.warn("Failed to update link", ose);
     throw new SynchronizationException(ose);
   }
 }
 /** {@inheritDoc} */
 @Override
 public Promise<List<Resource>, ResourceException> apply(final ResourceException error) {
   List<Promise<Resource, ResourceException>> promises =
       new ArrayList<Promise<Resource, ResourceException>>();
   PromiseImpl<Resource, ResourceException> kicker = PromiseImpl.create();
   promises.add(kicker);
   for (String id : policyIds) {
     promises.add(policyResource.handleDelete(context, Requests.newDeleteRequest(id)));
   }
   Promise<List<Resource>, ResourceException> promise =
       Promises.when(promises)
           .thenAsync(
               new AsyncFunction<List<Resource>, List<Resource>, ResourceException>() {
                 @Override
                 public Promise<List<Resource>, ResourceException> apply(List<Resource> value) {
                   // If we succeed in deleting then return the original error
                   return Promises.newExceptionPromise(error);
                 }
               });
   kicker.handleResult(null);
   return promise;
 }
  @Test
  public void crestQueryIsAllowed() throws SSOException, DelegationException, ResourceException {
    // Given...
    final Set<String> actions = new HashSet<>(Arrays.asList("READ"));
    final DelegationPermission permission =
        new DelegationPermission(
            "/abc", "rest", "1.0", "policies", "read", actions, EXTENSIONS, DUMB_FUNC);
    given(factory.newInstance("/abc", "rest", "1.0", "policies", "read", actions, EXTENSIONS))
        .willReturn(permission);

    given(subjectContext.getCallerSSOToken()).willReturn(token);
    given(evaluator.isAllowed(eq(token), eq(permission), eq(ENVIRONMENT))).willReturn(true);

    QueryResourceHandler handler = mock(QueryResourceHandler.class);
    Promise<QueryResponse, ResourceException> promise =
        Promises.newResultPromise(Responses.newQueryResponse("abc-def"));
    given(
            provider.queryCollection(
                isA(Context.class), isA(QueryRequest.class), isA(QueryResourceHandler.class)))
        .willReturn(promise);

    // When...
    final FilterChain chain = AuthorizationFilters.createAuthorizationFilter(provider, module);
    final Router router = new Router();
    router.addRoute(RoutingMode.STARTS_WITH, Router.uriTemplate("/policies"), chain);

    final RealmContext context = new RealmContext(subjectContext);
    context.setSubRealm("abc", "abc");
    final QueryRequest request = Requests.newQueryRequest("/policies");
    Promise<QueryResponse, ResourceException> result =
        router.handleQuery(context, request, handler);

    // Then...
    QueryResponse response = result.getOrThrowUninterruptibly();
    assertThat(response.getPagedResultsCookie()).isEqualTo("abc-def");
  }
  void doPatch(final HttpServletRequest req, final HttpServletResponse resp) {
    try {
      // Parse out the required API versions.
      final AcceptAPIVersion acceptVersion = parseAcceptAPIVersion(req);

      // Prepare response.
      prepareResponse(req, resp);

      // Validate request.
      preprocessRequest(req);
      if (req.getHeader(HEADER_IF_NONE_MATCH) != null) {
        // FIXME: i18n
        throw new PreconditionFailedException(
            "Use of If-None-Match not supported for PATCH requests");
      }

      final Map<String, String[]> parameters = req.getParameterMap();
      final PatchRequest request =
          Requests.newPatchRequest(getResourceName(req)).setRevision(getIfMatch(req));
      request.getPatchOperations().addAll(getJsonPatchContent(req));
      for (final Map.Entry<String, String[]> p : parameters.entrySet()) {
        final String name = p.getKey();
        final String[] values = p.getValue();
        if (HttpUtils.isMultiPartRequest(req.getContentType())) {
          // Ignore - multipart content adds form parts to the parameter set
        } else if (parseCommonParameter(name, values, request)) {
          continue;
        } else {
          request.setAdditionalParameter(name, asSingleValue(name, values));
        }
      }
      doRequest(req, resp, acceptVersion, request);
    } catch (final Exception e) {
      fail(req, resp, e);
    }
  }
  /**
   * Performs the query on the specified object and returns the associated results.
   *
   * <p>Queries are parametric; a set of named parameters is provided as the query criteria. The
   * query result is a JSON object structure composed of basic Java types.
   *
   * <p>The returned map is structured as follow: - The top level map contains meta-data about the
   * query, plus an entry with the actual result records. - The <code>QueryConstants</code> defines
   * the map keys, including the result records (QUERY_RESULT)
   *
   * @param context identifies the object to query.
   * @param request the parameters of the query to perform.
   * @return the query results, which includes meta-data and the result records in JSON object
   *     structure format.
   * @throws NotFoundException if the specified object could not be found.
   * @throws BadRequestException if the specified params contain invalid arguments, e.g. a query id
   *     that is not configured, a query expression that is invalid, or missing query substitution
   *     tokens.
   * @throws ForbiddenException if access to the object or specified query is forbidden.
   */
  @Override
  public Promise<QueryResponse, ResourceException> handleQuery(
      final Context context, final QueryRequest request, final QueryResourceHandler handler) {

    // If paged results are requested then decode the cookie in order to determine
    // the index of the first result to be returned.
    final int requestPageSize = request.getPageSize();

    // Cookie containing offset of last request
    final String pagedResultsCookie = request.getPagedResultsCookie();

    final boolean pagedResultsRequested = requestPageSize > 0;

    // index of first record (used for SKIP/OFFSET)
    final int firstResultIndex;

    if (pagedResultsRequested) {
      if (StringUtils.isNotEmpty(pagedResultsCookie)) {
        try {
          firstResultIndex = Integer.parseInt(pagedResultsCookie);
        } catch (final NumberFormatException e) {
          return new BadRequestException("Invalid paged results cookie").asPromise();
        }
      } else {
        firstResultIndex = Math.max(0, request.getPagedResultsOffset());
      }
    } else {
      firstResultIndex = 0;
    }

    // Once cookie is processed Queries.query() can rely on the offset.
    request.setPagedResultsOffset(firstResultIndex);

    try {
      List<ResourceResponse> results = query(request);
      for (ResourceResponse result : results) {
        handler.handleResource(result);
      }

      /*
       * Execute additional -count query if we are paging
       */
      final String nextCookie;
      // The number of results (if known)
      final int resultCount;

      if (pagedResultsRequested) {
        // count if requested
        switch (request.getTotalPagedResultsPolicy()) {
          case ESTIMATE:
          case EXACT:
            // Get total if -count query is available
            final String countQueryId = request.getQueryId() + "-count";
            if (queries.queryIdExists(countQueryId)) {
              QueryRequest countRequest = Requests.copyOfQueryRequest(request);
              countRequest.setQueryId(countQueryId);

              // Strip pagination parameters
              countRequest.setPageSize(0);
              countRequest.setPagedResultsOffset(0);
              countRequest.setPagedResultsCookie(null);

              List<ResourceResponse> countResult = query(countRequest);

              if (countResult != null && !countResult.isEmpty()) {
                resultCount = countResult.get(0).getContent().get("total").asInteger();
              } else {
                logger.debug("Count query {} failed.", countQueryId);
                resultCount = NO_COUNT;
              }
            } else {
              logger.debug("No count query found with id {}", countQueryId);
              resultCount = NO_COUNT;
            }
            break;
          case NONE:
          default:
            resultCount = NO_COUNT;
            break;
        }

        if (results.size() < requestPageSize) {
          nextCookie = null;
        } else {
          final int remainingResults = resultCount - (firstResultIndex + results.size());
          if (remainingResults == 0) {
            nextCookie = null;
          } else {
            nextCookie = String.valueOf(firstResultIndex + requestPageSize);
          }
        }
      } else {
        resultCount = NO_COUNT;
        nextCookie = null;
      }

      if (resultCount == NO_COUNT) {
        return newQueryResponse(nextCookie).asPromise();
      } else {
        return newQueryResponse(nextCookie, EXACT, resultCount).asPromise();
      }
    } catch (ResourceException e) {
      return e.asPromise();
    }
  }
  /**
   * Stores the <code>Dictionary</code> under the given <code>pid</code>.
   *
   * @param pid The identifier of the dictionary.
   * @param properties The <code>Dictionary</code> to store.
   * @throws IOException If an error occurrs storing the dictionary. If this exception is thrown, it
   *     is expected, that {@link #exists(String) exists(pid} returns <code>false</code>.
   */
  public void store(String pid, Dictionary properties) throws IOException {
    logger.debug("Store call for {} {}", pid, properties);

    // Store config handling settings in memory
    if (pid.startsWith("org.apache.felix.fileinstall")) {
      tempStore.put(pid, properties);
      return;
    }

    try {
      if (isReady(0) && requireRepository) {
        String id = pidToId(pid);

        Map<String, Object> obj = dictToMap(properties);
        JsonValue content = new JsonValue(obj);
        String configResourceId =
            ConfigBootstrapHelper.getId(
                content.get(ConfigBootstrapHelper.CONFIG_ALIAS).asString(),
                content.get(ConfigBootstrapHelper.SERVICE_PID).asString(),
                content.get(ConfigBootstrapHelper.SERVICE_FACTORY_PID).asString());
        String configString = (String) obj.get(JSONEnhancedConfig.JSON_CONFIG_PROPERTY);
        Map<Object, Object> configMap = deserializeConfig(configString);
        if (configMap != null) {
          configMap.put("_id", configResourceId);
        }
        obj.put(JSONEnhancedConfig.JSON_CONFIG_PROPERTY, configMap);

        Map<String, Object> existing = null;
        try {
          ReadRequest readRequest = Requests.newReadRequest(id);
          existing = repo.read(readRequest).getContent().asMap();
        } catch (NotFoundException ex) {
          // Just detect that it doesn't exist
        }
        if (existing != null) {
          String rev = (String) existing.get("_rev");

          existing.remove("_rev");
          existing.remove("_id");
          obj.remove("_rev"); // beware, this means _id and _rev should not be in config file
          obj.remove("_id"); // beware, this means _id and _rev should not be in config file
          obj.remove(RepoPersistenceManager.BUNDLE_LOCATION);
          obj.remove(RepoPersistenceManager.FELIX_FILEINSTALL_FILENAME);
          if (!existing.equals(obj)) {
            logger.trace("Not matching {} {}", existing, obj);
            boolean retry;
            do {
              retry = false;
              try {
                UpdateRequest r = Requests.newUpdateRequest(id, new JsonValue(obj));
                r.setRevision(rev);
                repo.update(r);
              } catch (PreconditionFailedException ex) {
                logger.debug("Concurrent change during update, retrying {} {}", pid, rev);
                ReadRequest readRequest = Requests.newReadRequest(id);
                existing = repo.read(readRequest).getContent().asMap();
                retry = true;
              }
            } while (retry);
            logger.debug("Updated existing config {} {} {}", new Object[] {pid, rev, obj});
          } else {
            logger.debug(
                "Existing config same as store request, ignoring {} {} {}",
                new Object[] {pid, rev, obj});
          }
        } else {
          logger.trace("Creating: {} {} ", id, obj);
          // This may create a new (empty) configuration, which felix marks with
          // _felix___cm__newConfiguration=true
          String newResourceId = id.substring(CONFIG_CONTEXT_PREFIX.length());
          CreateRequest createRequest =
              Requests.newCreateRequest(CONFIG_CONTEXT_PREFIX, new JsonValue(obj));
          createRequest.setNewResourceId(newResourceId);
          obj = repo.create(createRequest).getContent().asMap();
          logger.debug("Stored new config in repository {} {}", pid, obj);
        }
      } else {
        tempStore.put(pid, properties);
        logger.debug("Stored in memory {} {}", pid, properties);
      }
    } catch (ResourceException ex) {
      throw new IOException("Failed to store configuration in repository: " + ex.getMessage(), ex);
    }
  }
  void doPut(final HttpServletRequest req, final HttpServletResponse resp) {
    try {
      // Parse out the required API versions.
      final AcceptAPIVersion acceptVersion = parseAcceptAPIVersion(req);

      // Prepare response.
      prepareResponse(req, resp);

      // Validate request.
      preprocessRequest(req);

      if (req.getHeader(HEADER_IF_MATCH) != null && req.getHeader(HEADER_IF_NONE_MATCH) != null) {
        // FIXME: i18n
        throw new PreconditionFailedException(
            "Simultaneous use of If-Match and If-None-Match not " + "supported for PUT requests");
      }

      final Map<String, String[]> parameters = req.getParameterMap();
      final JsonValue content = getJsonContent(req);

      final String rev = getIfNoneMatch(req);
      if (ETAG_ANY.equals(rev)) {
        // This is a create with a user provided resource ID: split the
        // path into the parent resource name and resource ID.
        final String resourceName = getResourceName(req);
        final int i = resourceName.lastIndexOf('/');
        final CreateRequest request;
        if (resourceName.isEmpty()) {
          // FIXME: i18n.
          throw new BadRequestException("No new resource ID in HTTP PUT request");
        } else if (i < 0) {
          // We have a pathInfo of the form "{id}"
          request = Requests.newCreateRequest(EMPTY_STRING, content);
          request.setNewResourceId(resourceName);
        } else {
          // We have a pathInfo of the form "{container}/{id}"
          request = Requests.newCreateRequest(resourceName.substring(0, i), content);
          request.setNewResourceId(resourceName.substring(i + 1));
        }
        for (final Map.Entry<String, String[]> p : parameters.entrySet()) {
          final String name = p.getKey();
          final String[] values = p.getValue();
          if (HttpUtils.isMultiPartRequest(req.getContentType())) {
            // Ignore - multipart content adds form parts to the parameter set
          } else if (parseCommonParameter(name, values, request)) {
            continue;
          } else {
            request.setAdditionalParameter(name, asSingleValue(name, values));
          }
        }
        doRequest(req, resp, acceptVersion, request);
      } else {
        final UpdateRequest request =
            Requests.newUpdateRequest(getResourceName(req), content).setRevision(getIfMatch(req));
        for (final Map.Entry<String, String[]> p : parameters.entrySet()) {
          final String name = p.getKey();
          final String[] values = p.getValue();
          if (HttpUtils.isMultiPartRequest(req.getContentType())) {
            // Ignore - multipart content adds form parts to the parameter set
          } else if (parseCommonParameter(name, values, request)) {
            continue;
          } else {
            request.setAdditionalParameter(name, asSingleValue(name, values));
          }
        }
        doRequest(req, resp, acceptVersion, request);
      }
    } catch (final Exception e) {
      fail(req, resp, e);
    }
  }
  void doGet(final HttpServletRequest req, final HttpServletResponse resp) {
    try {
      // Parse out the required API versions.
      final AcceptAPIVersion acceptVersion = parseAcceptAPIVersion(req);

      // Prepare response.
      prepareResponse(req, resp);

      // Validate request.
      preprocessRequest(req);
      rejectIfMatch(req);

      final Map<String, String[]> parameters = req.getParameterMap();
      if (hasParameter(req, PARAM_QUERY_ID)
          || hasParameter(req, PARAM_QUERY_EXPRESSION)
          || hasParameter(req, PARAM_QUERY_FILTER)) {
        // Additional pre-validation for queries.
        rejectIfNoneMatch(req);

        // Query against collection.
        final QueryRequest request = Requests.newQueryRequest(getResourceName(req));

        for (final Map.Entry<String, String[]> p : parameters.entrySet()) {
          final String name = p.getKey();
          final String[] values = p.getValue();

          if (parseCommonParameter(name, values, request)) {
            continue;
          } else if (name.equalsIgnoreCase(PARAM_SORT_KEYS)) {
            for (final String s : values) {
              try {
                request.addSortKey(s.split(SORT_KEYS_DELIMITER));
              } catch (final IllegalArgumentException e) {
                // FIXME: i18n.
                throw new BadRequestException(
                    "The value '"
                        + s
                        + "' for parameter '"
                        + name
                        + "' could not be parsed as a comma "
                        + "separated list of sort keys");
              }
            }
          } else if (name.equalsIgnoreCase(PARAM_QUERY_ID)) {
            request.setQueryId(asSingleValue(name, values));
          } else if (name.equalsIgnoreCase(PARAM_QUERY_EXPRESSION)) {
            request.setQueryExpression(asSingleValue(name, values));
          } else if (name.equalsIgnoreCase(PARAM_PAGED_RESULTS_COOKIE)) {
            request.setPagedResultsCookie(asSingleValue(name, values));
          } else if (name.equalsIgnoreCase(PARAM_PAGED_RESULTS_OFFSET)) {
            request.setPagedResultsOffset(asIntValue(name, values));
          } else if (name.equalsIgnoreCase(PARAM_PAGE_SIZE)) {
            request.setPageSize(asIntValue(name, values));
          } else if (name.equalsIgnoreCase(PARAM_QUERY_FILTER)) {
            final String s = asSingleValue(name, values);
            try {
              request.setQueryFilter(QueryFilter.valueOf(s));
            } catch (final IllegalArgumentException e) {
              // FIXME: i18n.
              throw new BadRequestException(
                  "The value '"
                      + s
                      + "' for parameter '"
                      + name
                      + "' could not be parsed as a valid query filter");
            }
          } else {
            request.setAdditionalParameter(name, asSingleValue(name, values));
          }
        }

        // Check for incompatible arguments.
        if (request.getQueryId() != null && request.getQueryFilter() != null) {
          // FIXME: i18n.
          throw new BadRequestException(
              "The parameters "
                  + PARAM_QUERY_ID
                  + " and "
                  + PARAM_QUERY_FILTER
                  + " are mutually exclusive");
        }

        if (request.getQueryId() != null && request.getQueryExpression() != null) {
          // FIXME: i18n.
          throw new BadRequestException(
              "The parameters "
                  + PARAM_QUERY_ID
                  + " and "
                  + PARAM_QUERY_EXPRESSION
                  + " are mutually exclusive");
        }

        if (request.getQueryFilter() != null && request.getQueryExpression() != null) {
          // FIXME: i18n.
          throw new BadRequestException(
              "The parameters "
                  + PARAM_QUERY_FILTER
                  + " and "
                  + PARAM_QUERY_EXPRESSION
                  + " are mutually exclusive");
        }

        doRequest(req, resp, acceptVersion, request);
      } else {
        // Read of instance within collection or singleton.
        final String rev = getIfNoneMatch(req);
        if (ETAG_ANY.equals(rev)) {
          // FIXME: i18n
          throw new PreconditionFailedException(
              "If-None-Match * not appropriate for " + getMethod(req) + " requests");
        }

        final ReadRequest request = Requests.newReadRequest(getResourceName(req));
        for (final Map.Entry<String, String[]> p : parameters.entrySet()) {
          final String name = p.getKey();
          final String[] values = p.getValue();
          if (parseCommonParameter(name, values, request)) {
            continue;
          } else if (PARAM_MIME_TYPE.equalsIgnoreCase(name)) {
            if (values.length != 1 || values[0].split(FIELDS_DELIMITER).length > 1) {
              // FIXME: i18n.
              throw new BadRequestException("Only one mime type value allowed");
            }
            if (parameters.get(PARAM_FIELDS).length != 1) {
              // FIXME: i18n.
              throw new BadRequestException(
                  "The mime type parameter requires only 1 field to be specified");
            }
          } else {
            request.setAdditionalParameter(name, asSingleValue(name, values));
          }
        }
        doRequest(req, resp, acceptVersion, request);
      }
    } catch (final Exception e) {
      fail(req, resp, e);
    }
  }