@Test
  public void createAuthenticatableResource_notAuthorized_shouldFail() {
    final String domainName = generateDomain();
    final String resourceClassName = generateResourceClass(true, false);
    final char[] password = generateUniquePassword();
    final String externalId = generateUniqueExternalId();

    generateResourceAndAuthenticate();

    // attempt to create authenticatable resource without create-permission authorization
    try {
      accessControlContext.createResource(
          resourceClassName, domainName, PasswordCredentials.newInstance(password));
      fail("creating authenticatable resource without authorization should fail");
    } catch (NotAuthorizedException e) {
      assertThat(e.getMessage().toLowerCase(), containsString("create resource"));
    }
    try {
      accessControlContext.createResource(
          resourceClassName, domainName, externalId, PasswordCredentials.newInstance(password));
      fail("creating authenticatable resource without authorization should fail");
    } catch (NotAuthorizedException e) {
      assertThat(e.getMessage().toLowerCase(), containsString("create resource"));
    }
  }
  @Test
  public void createAuthenticatableResource_withExtId_validAsUnauthenticated() {
    final String domainName = generateDomain();
    final String resourceClassName = generateResourceClass(true, true);
    final String permissionName = generateResourceClassPermission(resourceClassName);
    final String permissionName2 = generateResourceClassPermission(resourceClassName);
    final char[] password = generateUniquePassword();
    final String externalId = generateUniqueExternalId();

    // (ironically,) set up an authenticatable resource with resource class create permission
    final Resource authenticatedResource = generateResourceAndAuthenticate();
    grantResourceCreatePermission(authenticatedResource, resourceClassName, domainName);

    final ResourcePermission implicitResourcePermission =
        ResourcePermissions.getInstance(permissionName);
    final ResourcePermission implicitResourcePermission2 =
        ResourcePermissions.getInstance(permissionName2);
    Set<Resource> resourcesByPermission =
        accessControlContext.getResourcesByResourcePermissions(
            authenticatedResource, resourceClassName, implicitResourcePermission);
    assertThat(resourcesByPermission.isEmpty(), is(true));
    Set<Resource> resourcesByPermission2 =
        accessControlContext.getResourcesByResourcePermissions(
            authenticatedResource, resourceClassName, implicitResourcePermission2);
    assertThat(resourcesByPermission2.isEmpty(), is(true));

    // create resource while unauthenticated and verify
    accessControlContext.unauthenticate();
    final Resource resource =
        accessControlContext.createResource(
            resourceClassName, domainName, externalId, PasswordCredentials.newInstance(password));

    assertThat(resource, is(not(nullValue())));
    assertThat(resource.getExternalId(), is(externalId));
    // re-authenticate as System Resource (because we don't have the previous credentials) and
    // verify created resource
    authenticateSystemResource();
    assertThat(accessControlContext.getDomainNameByResource(resource), is(domainName));
    final ResourceClassInfo resourceClassInfo =
        accessControlContext.getResourceClassInfoByResource(resource);
    assertThat(resourceClassInfo.getResourceClassName(), is(resourceClassName));

    // verify resource created while unauthenticated gets *ALL* available resource class permissions
    resourcesByPermission =
        accessControlContext.getResourcesByResourcePermissions(
            SYS_RESOURCE, resourceClassName, implicitResourcePermission);
    assertThat(resourcesByPermission.size(), is(1));
    resourcesByPermission2 =
        accessControlContext.getResourcesByResourcePermissions(
            SYS_RESOURCE, resourceClassName, implicitResourcePermission2);
    assertThat(resourcesByPermission2.size(), is(1));

    // verify we can authenticate
    accessControlContext.authenticate(resource, PasswordCredentials.newInstance(password));
  }
  @Test
  public void getResourceClassInfoByResource_nonExistentReferences_shouldFail() {
    authenticateSystemResource();

    final char[] password = generateUniquePassword();
    final Resource accessorResource = generateAuthenticatableResource(password);

    generateResourceClass(false, false);

    // authenticate and verify
    accessControlContext.authenticate(accessorResource, PasswordCredentials.newInstance(password));

    try {
      accessControlContext.getResourceClassInfoByResource(Resources.getInstance(-999L));
      fail("getting resource class info by resource for non-existent resource should have failed");
    } catch (IllegalArgumentException e) {
      assertThat(e.getMessage().toLowerCase(), containsString("not found"));
    }
    try {
      accessControlContext.getResourceClassInfoByResource(Resources.getInstance("invalid"));
      fail(
          "getting resource class info by resource for non-existent external resource reference should have failed");
    } catch (IllegalArgumentException e) {
      assertThat(e.getMessage().toLowerCase(), containsString("not found"));
    }
    try {
      accessControlContext.getResourceClassInfoByResource(Resources.getInstance(-999L, "invalid"));
      fail(
          "getting resource class info by resource for mismatched internal/external resource ids should have failed");
    } catch (IllegalArgumentException e) {
      assertThat(e.getMessage().toLowerCase(), containsString("not resolve"));
    }
  }
  @Test
  public void getResourceClassInfoByResource_nulls() {
    final char[] password = generateUniquePassword();
    final Resource accessorResource = generateAuthenticatableResource(password);

    generateResourceClass(false, false);

    // authenticate and verify
    accessControlContext.authenticate(accessorResource, PasswordCredentials.newInstance(password));

    try {
      accessControlContext.getResourceClassInfoByResource(null);
      fail("getting resource class info by resource for null resource should have failed");
    } catch (NullPointerException e) {
      assertThat(e.getMessage().toLowerCase(), containsString("resource required"));
    }
    try {
      accessControlContext.getResourceClassInfoByResource(Resources.getInstance(null));
      fail(
          "getting resource class info by resource for null internal/external resource ids should have failed");
    } catch (IllegalArgumentException e) {
      assertThat(
          e.getMessage().toLowerCase(),
          containsString("resource id and/or external id is required"));
    }
  }
  @Test
  public void createAuthenticatableResource_nonExistentReferences_shouldFail() {
    authenticateSystemResource();

    final String domainName = generateDomain();
    final String resourceClassName = generateResourceClass(true, false);
    final char[] password = generateUniquePassword();
    final String externalId = generateUniqueExternalId();

    // attempt to create authenticatable resources with non-existent references to class or domain
    // names
    try {
      accessControlContext.createResource(
          "does_not_exist", domainName, PasswordCredentials.newInstance(password));
      fail("creating authenticatable resource with non-existent resource class name should fail");
    } catch (IllegalArgumentException e) {
      assertThat(e.getMessage().toLowerCase(), containsString("could not find resource class"));
    }
    try {
      accessControlContext.createResource(
          "does_not_exist", domainName, externalId, PasswordCredentials.newInstance(password));
      fail("creating authenticatable resource with non-existent resource class name should fail");
    } catch (IllegalArgumentException e) {
      assertThat(e.getMessage().toLowerCase(), containsString("could not find resource class"));
    }

    try {
      accessControlContext.createResource(
          resourceClassName, "does_not_exist", PasswordCredentials.newInstance(password));
      fail("creating authenticatable resource with non-existent domain name should have failed");
    } catch (IllegalArgumentException e) {
      assertThat(e.getMessage().toLowerCase(), containsString("could not find domain"));
    }
    try {
      accessControlContext.createResource(
          resourceClassName,
          "does_not_exist",
          externalId,
          PasswordCredentials.newInstance(password));
      fail("creating authenticatable resource with non-existent domain name should have failed");
    } catch (IllegalArgumentException e) {
      assertThat(e.getMessage().toLowerCase(), containsString("could not find domain"));
    }
  }
  @Test
  public void createAuthenticatableResource_withExtId_validAsAuthorized() {
    final String domainName = generateDomain();
    final String resourceClassName = generateResourceClass(true, false);
    final char[] password = generateUniquePassword();
    final char[] passwordBase = generateUniquePassword();
    final char[] shortPwd = (passwordBase + "123").substring(0, 3).toCharArray();
    final char[] whitespacedPwd = (" " + passwordBase + "\t").toCharArray();
    final String externalId = generateUniqueExternalId();

    // (ironically,) set up an authenticatable resource with resource class create permission
    final Resource authenticatedResource = generateResourceAndAuthenticate();
    final String permissionName = generateResourceClassPermission(resourceClassName);
    final ResourcePermission grantedResourcePermission =
        ResourcePermissions.getInstance(permissionName);
    grantResourceCreatePermission(
        authenticatedResource, resourceClassName, domainName, permissionName);

    Set<Resource> resourcesByPermission =
        accessControlContext.getResourcesByResourcePermissions(
            authenticatedResource, resourceClassName, grantedResourcePermission);
    assertThat(resourcesByPermission.isEmpty(), is(true));

    // create resource and verify
    final Resource resource =
        accessControlContext.createResource(
            resourceClassName, domainName, externalId, PasswordCredentials.newInstance(password));

    assertThat(resource, is(not(nullValue())));
    resourcesByPermission =
        accessControlContext.getResourcesByResourcePermissions(
            authenticatedResource, resourceClassName, grantedResourcePermission);
    assertThat(resourcesByPermission.size(), is(1));
    assertThat(accessControlContext.getDomainNameByResource(resource), is(domainName));
    final ResourceClassInfo resourceClassInfo =
        accessControlContext.getResourceClassInfoByResource(resource);
    assertThat(resourceClassInfo.getResourceClassName(), is(resourceClassName));
    assertThat(resource.getExternalId(), is(externalId));

    // verify we can authenticate
    accessControlContext.authenticate(resource, PasswordCredentials.newInstance(password));
  }
  @Test
  public void createAuthenticatableResource_validAsSystemResource() {
    authenticateSystemResource();

    final String domainName = generateDomain();
    final String resourceClassName = generateResourceClass(true, false);
    final char[] password = generateUniquePassword();

    // create resource and verify
    final Resource resource =
        accessControlContext.createResource(
            resourceClassName, domainName, PasswordCredentials.newInstance(password));

    assertThat(resource, is(not(nullValue())));
    accessControlContext.authenticate(resource, PasswordCredentials.newInstance(password));
    assertThat(accessControlContext.getDomainNameByResource(resource), is(domainName));
    final ResourceClassInfo resourceClassInfo =
        accessControlContext.getResourceClassInfoByResource(resource);
    assertThat(resourceClassInfo.getResourceClassName(), is(resourceClassName));
  }
  @Test
  public void createAuthenticatableResource_unauthenticatableResourceClass_shouldFail() {
    authenticateSystemResource();

    final String domainName = generateDomain();
    final String resourceClassName = generateResourceClass(false, false);
    final char[] password = generateUniquePassword();

    // attempt to create authenticatable resource for unauthenticatable resource class
    try {
      accessControlContext.createResource(
          resourceClassName, domainName, PasswordCredentials.newInstance(password));
      fail(
          "creating authenticatable resource for unauthenticatable resource class name should have failed");
    } catch (IllegalArgumentException e) {
      assertThat(
          e.getMessage().toLowerCase(), containsString("credentials not supported, but specified"));
    }
  }
  @Test
  public void getResourceClassInfoByResource_validAsSystemResource() {
    authenticateSystemResource();

    generateUnauthenticatableResource();
    final String resourceClassName = generateResourceClass(true, false);
    final Resource queriedResource =
        accessControlContext.createResource(
            resourceClassName,
            accessControlContext.getDomainNameByResource(SYS_RESOURCE),
            PasswordCredentials.newInstance(generateUniquePassword()));

    // verify
    final ResourceClassInfo resourceClassInfo =
        accessControlContext.getResourceClassInfoByResource(queriedResource);
    assertThat(resourceClassInfo, is(not(nullValue())));
    assertThat(resourceClassInfo.getResourceClassName(), is(resourceClassName));
    assertThat(resourceClassInfo.isAuthenticatable(), is(true));
    assertThat(resourceClassInfo.isUnauthenticatedCreateAllowed(), is(false));
  }
  @Test
  public void createAuthenticatableResource_invalidPassword_shouldFail() {
    authenticateSystemResource();

    final String domainName = generateDomain();
    final String resourceClassName = generateResourceClass(true, false);

    // attempt to create authenticatable resource with invalid passwords
    try {
      accessControlContext.createResource(resourceClassName, domainName, (Credentials) null);
      fail("creating authenticatable resource with null credentials should have failed");
    } catch (NullPointerException e) {
      assertThat(e.getMessage().toLowerCase(), containsString("credentials required"));
    }

    try {
      accessControlContext.createResource(
          resourceClassName, domainName, PasswordCredentials.newInstance(null));
      fail("creating authenticatable resource with null password should have failed");
    } catch (InvalidCredentialsException e) {
      assertThat(e.getMessage().toLowerCase(), containsString("password required, none specified"));
    }
  }
  @Test
  public void createAuthenticatableResource_duplicateExternalId_shouldFail() {
    authenticateSystemResource();

    final String domainName1 = generateDomain();
    final String resourceClassName1 = generateResourceClass(true, false);
    final String domainName2 = generateDomain();
    final String resourceClassName2 = generateResourceClass(true, false);
    final Credentials password = PasswordCredentials.newInstance(generateUniquePassword());
    final String externalId = generateUniqueExternalId();

    // create resource
    final Resource resource =
        accessControlContext.createResource(resourceClassName1, domainName1, externalId, password);
    assertThat(resource.getExternalId(), is(externalId));

    // create resource with same external id and verify
    try {
      accessControlContext.createResource(resourceClassName2, domainName2, externalId, password);
      fail("creating resource with duplicate (i.e. non-unique) external id should have failed");
    } catch (IllegalArgumentException e) {
      assertThat(e.getMessage().toLowerCase(), containsString("external id is not unique"));
    }
  }
  @Test
  public void createAuthenticatableResource_blankNames_shouldFail() {
    authenticateSystemResource();

    final String domainName = generateDomain();
    final String resourceClassName = generateResourceClass(true, false);
    final char[] password = generateUniquePassword();
    final String externalId = generateUniqueExternalId();

    // attempt to create authenticatable resources with empty or whitespaced parameters
    try {
      accessControlContext.createResource(
          "", domainName, PasswordCredentials.newInstance(password));
      fail("creating authenticatable resource with empty resource class name should have failed");
    } catch (IllegalArgumentException e) {
      assertThat(e.getMessage().toLowerCase(), containsString("resource class required"));
    }
    try {
      accessControlContext.createResource(
          "", domainName, externalId, PasswordCredentials.newInstance(password));
      fail("creating authenticatable resource with empty resource class name should have failed");
    } catch (IllegalArgumentException e) {
      assertThat(e.getMessage().toLowerCase(), containsString("resource class required"));
    }
    try {
      accessControlContext.createResource(
          " \t", domainName, PasswordCredentials.newInstance(password));
      fail("creating authenticatable resource with empty resource class name should have failed");
    } catch (IllegalArgumentException e) {
      assertThat(e.getMessage().toLowerCase(), containsString("resource class required"));
    }
    try {
      accessControlContext.createResource(
          " \t", domainName, externalId, PasswordCredentials.newInstance(password));
      fail("creating authenticatable resource with empty resource class name should have failed");
    } catch (IllegalArgumentException e) {
      assertThat(e.getMessage().toLowerCase(), containsString("resource class required"));
    }

    try {
      accessControlContext.createResource(
          resourceClassName, "", PasswordCredentials.newInstance(password));
      fail("creating authenticatable resource with empty domain name should have failed");
    } catch (IllegalArgumentException e) {
      assertThat(e.getMessage().toLowerCase(), containsString("domain required"));
    }
    try {
      accessControlContext.createResource(
          resourceClassName, "", externalId, PasswordCredentials.newInstance(password));
      fail("creating authenticatable resource with empty domain name should have failed");
    } catch (IllegalArgumentException e) {
      assertThat(e.getMessage().toLowerCase(), containsString("domain required"));
    }
    try {
      accessControlContext.createResource(
          resourceClassName, " \t", PasswordCredentials.newInstance(password));
      fail("creating authenticatable resource with empty domain name should have failed");
    } catch (IllegalArgumentException e) {
      assertThat(e.getMessage().toLowerCase(), containsString("domain required"));
    }
    try {
      accessControlContext.createResource(
          resourceClassName, " \t", externalId, PasswordCredentials.newInstance(password));
      fail("creating authenticatable resource with empty domain name should have failed");
    } catch (IllegalArgumentException e) {
      assertThat(e.getMessage().toLowerCase(), containsString("domain required"));
    }

    try {
      accessControlContext.createResource(
          resourceClassName, domainName, "", PasswordCredentials.newInstance(password));
      fail("creating authenticatable resource with empty external id should have failed");
    } catch (IllegalArgumentException e) {
      assertThat(e.getMessage().toLowerCase(), containsString("external id required"));
    }
    try {
      accessControlContext.createResource(
          resourceClassName, domainName, " \t", PasswordCredentials.newInstance(password));
      fail("creating authenticatable resource with empty external id should have failed");
    } catch (IllegalArgumentException e) {
      assertThat(e.getMessage().toLowerCase(), containsString("external id required"));
    }

    try {
      accessControlContext.createResource(
          resourceClassName, domainName, PasswordCredentials.newInstance("".toCharArray()));
      fail("creating authenticatable resource with empty password should have failed");
    } catch (InvalidCredentialsException e) {
      assertThat(e.getMessage().toLowerCase(), containsString("password cannot be zero length"));
    }
    try {
      accessControlContext.createResource(
          resourceClassName,
          domainName,
          externalId,
          PasswordCredentials.newInstance("".toCharArray()));
      fail("creating authenticatable resource with empty password should have failed");
    } catch (InvalidCredentialsException e) {
      assertThat(e.getMessage().toLowerCase(), containsString("password cannot be zero length"));
    }
    try {
      accessControlContext.createResource(
          resourceClassName,
          domainName,
          externalId,
          PasswordCredentials.newInstance(" \t".toCharArray()));
      fail("creating authenticatable resource with empty password should have failed");
    } catch (InvalidCredentialsException e) {
      assertThat(e.getMessage().toLowerCase(), containsString("password cannot be blank"));
    }
    try {
      accessControlContext.createResource(
          resourceClassName, domainName, PasswordCredentials.newInstance(" \t".toCharArray()));
      fail("creating authenticatable resource with empty password should have failed");
    } catch (InvalidCredentialsException e) {
      assertThat(e.getMessage().toLowerCase(), containsString("password cannot be blank"));
    }
  }
  @Test
  public void createAuthenticatableResource_nulls_shouldFail() {
    authenticateSystemResource();

    final String domainName = generateDomain();
    final String resourceClassName = generateResourceClass(true, false);
    final char[] password = generateUniquePassword();
    final String externalId = generateUniqueExternalId();

    // attempt to create resources with null parameters
    try {
      accessControlContext.createResource(
          null, domainName, PasswordCredentials.newInstance(password));
      fail("creating authenticatable resource with null resource class name should have failed");
    } catch (NullPointerException e) {
      assertThat(e.getMessage().toLowerCase(), containsString("resource class required"));
    }
    try {
      accessControlContext.createResource(
          null, domainName, externalId, PasswordCredentials.newInstance(password));
      fail("creating authenticatable resource with null resource class name should have failed");
    } catch (NullPointerException e) {
      assertThat(e.getMessage().toLowerCase(), containsString("resource class required"));
    }

    try {
      accessControlContext.createResource(
          resourceClassName, null, PasswordCredentials.newInstance(password));
      fail("creating authenticatable resource with null domain name should have failed");
    } catch (NullPointerException e) {
      assertThat(e.getMessage().toLowerCase(), containsString("domain required"));
    }
    try {
      accessControlContext.createResource(
          resourceClassName, null, externalId, PasswordCredentials.newInstance(password));
      fail("creating authenticatable resource with null domain name should have failed");
    } catch (NullPointerException e) {
      assertThat(e.getMessage().toLowerCase(), containsString("domain required"));
    }

    try {
      accessControlContext.createResource(
          resourceClassName, domainName, null, PasswordCredentials.newInstance(password));
      fail("creating authenticatable resource with null external id should have failed");
    } catch (NullPointerException e) {
      assertThat(e.getMessage().toLowerCase(), containsString("external id required"));
    }

    try {
      accessControlContext.createResource(resourceClassName, domainName, (Credentials) null);
      fail("creating authenticatable resource with null credentials should have failed");
    } catch (NullPointerException e) {
      assertThat(
          e.getMessage().toLowerCase(), containsString("credentials required, none specified"));
    }
    try {
      accessControlContext.createResource(resourceClassName, domainName, externalId, null);
      fail("creating authenticatable resource with null credentials should have failed");
    } catch (NullPointerException e) {
      assertThat(
          e.getMessage().toLowerCase(), containsString("credentials required, none specified"));
    }

    try {
      accessControlContext.createResource(
          resourceClassName, domainName, PasswordCredentials.newInstance(null));
      fail("creating authenticatable resource with null password should have failed");
    } catch (InvalidCredentialsException e) {
      assertThat(e.getMessage().toLowerCase(), containsString("password required, none specified"));
    }
    try {
      accessControlContext.createResource(
          resourceClassName, domainName, externalId, PasswordCredentials.newInstance(null));
      fail("creating authenticatable resource with null password should have failed");
    } catch (InvalidCredentialsException e) {
      assertThat(e.getMessage().toLowerCase(), containsString("password required, none specified"));
    }
  }
  @Test
  public void createAuthenticatableResource_caseSensitiveConsistent_duplicateExternalId() {
    authenticateSystemResource();

    final String domainName = generateDomain();
    final String resourceClassName = generateResourceClass(true, false);
    final String permissionName = generateUniquePermissionName();
    final Credentials password = PasswordCredentials.newInstance(generateUniquePassword());
    final String externalId = generateUniqueExternalId();
    final String externalId_lower = externalId + "_eee";
    final String externalId_UPPER = externalId + "_EEE";

    accessControlContext.createResourcePermission(resourceClassName, permissionName);

    // set up an authenticatable resource with resource class create permission
    // so that we can look up the resources later via that permission
    final Resource authenticatedResource = generateResourceAndAuthenticate();
    grantResourceCreatePermission(
        authenticatedResource, resourceClassName, domainName, permissionName);
    final ResourcePermission grantedResourcePermission =
        ResourcePermissions.getInstance(permissionName);

    Set<Resource> resourcesByPermission;
    resourcesByPermission =
        accessControlContext.getResourcesByResourcePermissions(
            authenticatedResource, resourceClassName, grantedResourcePermission);
    assertThat(resourcesByPermission.isEmpty(), is(true));

    // check case sensitivity
    if (isDatabaseCaseSensitive()) {
      // create resource
      final Resource resource =
          accessControlContext.createResource(
              resourceClassName, domainName, externalId_lower, password);
      assertThat(resource.getExternalId(), is(externalId_lower));

      // create resource with same but case-sensitive external id and verify
      final Resource resource2 =
          accessControlContext.createResource(
              resourceClassName, domainName, externalId_UPPER, password);
      assertThat(resource2.getExternalId(), is(externalId_UPPER));

      resourcesByPermission =
          accessControlContext.getResourcesByResourcePermissions(
              authenticatedResource, resourceClassName, grantedResourcePermission);
      assertThat(resourcesByPermission.size(), is(2));
    } else {
      // create resource
      final Resource resource =
          accessControlContext.createResource(
              resourceClassName, domainName, externalId_lower, password);
      assertThat(resource.getExternalId(), is(externalId_lower));

      // create resource with same but case-insensitive external id and verify
      try {
        accessControlContext.createResource(
            resourceClassName, domainName, externalId_UPPER, password);
        fail(
            "creating resource with external id that differs in case should have failed for case-insensitive database");
      } catch (IllegalArgumentException e) {
        assertThat(e.getMessage().toLowerCase(), containsString("external id is not unique"));
      }

      resourcesByPermission =
          accessControlContext.getResourcesByResourcePermissions(
              authenticatedResource, resourceClassName, grantedResourcePermission);
      assertThat(resourcesByPermission.size(), is(1));
    }
  }
  @Test
  public void createAuthenticatableResource_caseSensitiveConsistent_AsAuthorized() {
    authenticateSystemResource();
    final String domainBase = generateUniqueDomainName();
    final String resourceClassBase = generateUniqueResourceClassName();
    final String domain_lower = domainBase + "_ddd";
    final String domain_UPPER = domainBase + "_DDD";
    final String resourceClass_lower = resourceClassBase + "_ccc";
    final String resourceClass_UPPER = resourceClassBase + "_CCC";
    final String permissionName = generateUniquePermissionName();
    final char[] passwordBase = generateUniquePassword();
    final char[] password_lower = (passwordBase + "_pwd").toCharArray();
    final char[] password_UPPER = (passwordBase + "_PWD").toCharArray();
    accessControlContext.createDomain(domain_lower);
    accessControlContext.createResourceClass(resourceClass_lower, true, false);
    accessControlContext.createResourcePermission(resourceClass_lower, permissionName);

    if (isDatabaseCaseSensitive()) {
      accessControlContext.createDomain(domain_UPPER);
      accessControlContext.createResourceClass(resourceClass_UPPER, true, false);
      accessControlContext.createResourcePermission(resourceClass_UPPER, permissionName);

      // set up an authenticatable resource with resource class create permission
      // and an extra permission in each domain/class combo, so that we can look up
      // the resources later via that permission
      final Resource authenticatedResource = generateResourceAndAuthenticate();
      grantResourceCreatePermission(
          authenticatedResource, resourceClass_lower, domain_lower, permissionName);
      grantResourceCreatePermission(
          authenticatedResource, resourceClass_lower, domain_UPPER, permissionName);
      grantResourceCreatePermission(
          authenticatedResource, resourceClass_UPPER, domain_lower, permissionName);
      grantResourceCreatePermission(
          authenticatedResource, resourceClass_UPPER, domain_UPPER, permissionName);
      final ResourcePermission grantedResourcePermission_lower =
          ResourcePermissions.getInstance(permissionName);
      final ResourcePermission grantedResourcePermission_UPPER =
          ResourcePermissions.getInstance(permissionName);

      Set<Resource> resourcesByPermission;
      resourcesByPermission =
          accessControlContext.getResourcesByResourcePermissions(
              authenticatedResource, resourceClass_lower, grantedResourcePermission_lower);
      assertThat(resourcesByPermission.isEmpty(), is(true));
      resourcesByPermission =
          accessControlContext.getResourcesByResourcePermissions(
              authenticatedResource, resourceClass_UPPER, grantedResourcePermission_UPPER);
      assertThat(resourcesByPermission.isEmpty(), is(true));

      // create resources with case-sensitive domain/class names and verify resources get created in
      // different domain/classes
      final Resource resource_lowlow =
          accessControlContext.createResource(
              resourceClass_lower, domain_lower, PasswordCredentials.newInstance(password_lower));
      assertThat(resource_lowlow, is(not(nullValue())));
      resourcesByPermission =
          accessControlContext.getResourcesByResourcePermissions(
              authenticatedResource, resourceClass_lower, grantedResourcePermission_lower);
      assertThat(resourcesByPermission.size(), is(1));

      final Resource resource_lowUP =
          accessControlContext.createResource(
              resourceClass_lower, domain_UPPER, PasswordCredentials.newInstance(password_UPPER));
      assertThat(resource_lowUP, is(not(nullValue())));
      assertThat(resource_lowUP.getId(), is(not(resource_lowlow.getId())));
      resourcesByPermission =
          accessControlContext.getResourcesByResourcePermissions(
              authenticatedResource, resourceClass_lower, grantedResourcePermission_lower);
      assertThat(resourcesByPermission.size(), is(2));

      final Resource resource_UPlow =
          accessControlContext.createResource(
              resourceClass_UPPER, domain_lower, PasswordCredentials.newInstance(password_lower));
      assertThat(resource_UPlow, is(not(nullValue())));
      resourcesByPermission =
          accessControlContext.getResourcesByResourcePermissions(
              authenticatedResource, resourceClass_UPPER, grantedResourcePermission_UPPER);
      assertThat(resourcesByPermission.size(), is(1));

      final Resource resource_UPUP =
          accessControlContext.createResource(
              resourceClass_UPPER, domain_UPPER, PasswordCredentials.newInstance(password_UPPER));
      assertThat(resource_UPUP, is(not(nullValue())));
      assertThat(resource_UPUP.getId(), is(not(resource_UPlow.getId())));
      resourcesByPermission =
          accessControlContext.getResourcesByResourcePermissions(
              authenticatedResource, resourceClass_UPPER, grantedResourcePermission_UPPER);
      assertThat(resourcesByPermission.size(), is(2));

      // verify passwords are case-sensitive
      accessControlContext.authenticate(
          resource_lowlow, PasswordCredentials.newInstance(password_lower));
      accessControlContext.authenticate(
          resource_UPUP, PasswordCredentials.newInstance(password_UPPER));
      try {
        accessControlContext.authenticate(
            resource_lowlow, PasswordCredentials.newInstance(password_UPPER));
        fail(
            "authentication of system resource with case-insensitive password should not have succeeded");
      } catch (IncorrectCredentialsException e) {
        assertThat(e.getMessage().toLowerCase(), containsString("invalid password"));
      }
      try {
        accessControlContext.authenticate(
            resource_UPUP, PasswordCredentials.newInstance(password_lower));
        fail(
            "authentication of system resource with case-insensitive password should not have succeeded");
      } catch (IncorrectCredentialsException e) {
        assertThat(e.getMessage().toLowerCase(), containsString("invalid password"));
      }
    } else {
      // set up an authenticatable resource with resource class create permission
      // and an extra permission in each domain/class combo, so that we can look up
      // the resources later via that permission
      final Resource authenticatedResource = generateResourceAndAuthenticate();
      grantResourceCreatePermission(
          authenticatedResource, resourceClass_lower, domain_lower, permissionName);
      final ResourcePermission grantedResourcePermission =
          ResourcePermissions.getInstance(permissionName);

      Set<Resource> resourcesByPermission;
      resourcesByPermission =
          accessControlContext.getResourcesByResourcePermissions(
              authenticatedResource, resourceClass_lower, grantedResourcePermission);
      assertThat(resourcesByPermission.isEmpty(), is(true));
      resourcesByPermission =
          accessControlContext.getResourcesByResourcePermissions(
              authenticatedResource, resourceClass_UPPER, grantedResourcePermission);
      assertThat(resourcesByPermission.isEmpty(), is(true));

      // create resources with case-sensitive domain/class names and verify resources get created in
      // different domain/classes
      final Resource resource_lowlow =
          accessControlContext.createResource(
              resourceClass_lower, domain_lower, PasswordCredentials.newInstance(password_lower));
      assertThat(resource_lowlow, is(not(nullValue())));
      resourcesByPermission =
          accessControlContext.getResourcesByResourcePermissions(
              authenticatedResource, resourceClass_lower, grantedResourcePermission);
      assertThat(resourcesByPermission.size(), is(1));

      final Resource resource_lowUP =
          accessControlContext.createResource(
              resourceClass_lower, domain_UPPER, PasswordCredentials.newInstance(password_UPPER));
      assertThat(resource_lowUP, is(not(nullValue())));
      assertThat(resource_lowUP.getId(), is(not(resource_lowlow.getId())));
      resourcesByPermission =
          accessControlContext.getResourcesByResourcePermissions(
              authenticatedResource, resourceClass_lower, grantedResourcePermission);
      assertThat(resourcesByPermission.size(), is(2));

      final Resource resource_UPlow =
          accessControlContext.createResource(
              resourceClass_UPPER, domain_lower, PasswordCredentials.newInstance(password_lower));
      assertThat(resource_UPlow, is(not(nullValue())));
      assertThat(resource_UPlow.getId(), is(not(resource_lowlow.getId())));
      assertThat(resource_UPlow.getId(), is(not(resource_lowUP.getId())));
      resourcesByPermission =
          accessControlContext.getResourcesByResourcePermissions(
              authenticatedResource, resourceClass_UPPER, grantedResourcePermission);
      assertThat(resourcesByPermission.size(), is(3));

      final Resource resource_UPUP =
          accessControlContext.createResource(
              resourceClass_UPPER, domain_UPPER, PasswordCredentials.newInstance(password_UPPER));
      assertThat(resource_UPUP, is(not(nullValue())));
      assertThat(resource_UPUP.getId(), is(not(resource_lowlow.getId())));
      assertThat(resource_UPUP.getId(), is(not(resource_lowUP.getId())));
      assertThat(resource_UPUP.getId(), is(not(resource_UPlow.getId())));
      resourcesByPermission =
          accessControlContext.getResourcesByResourcePermissions(
              authenticatedResource, resourceClass_UPPER, grantedResourcePermission);
      assertThat(resourcesByPermission.size(), is(4));

      // verify passwords are case-sensitive
      accessControlContext.authenticate(
          resource_lowlow, PasswordCredentials.newInstance(password_lower));
      accessControlContext.authenticate(
          resource_UPUP, PasswordCredentials.newInstance(password_UPPER));
      try {
        accessControlContext.authenticate(
            resource_lowlow, PasswordCredentials.newInstance(password_UPPER));
        fail(
            "authentication of system resource with case-insensitive password should not have succeeded");
      } catch (IncorrectCredentialsException e) {
        assertThat(e.getMessage().toLowerCase(), containsString("invalid password"));
      }
      try {
        accessControlContext.authenticate(
            resource_UPUP, PasswordCredentials.newInstance(password_lower));
        fail(
            "authentication of system resource with case-insensitive password should not have succeeded");
      } catch (IncorrectCredentialsException e) {
        assertThat(e.getMessage().toLowerCase(), containsString("invalid password"));
      }
    }
  }
  @Test
  public void createAuthenticatableResource_whitespaceConsistent_AsAuthorized() {
    final String domainName = generateDomain();
    final String resourceClassName = generateResourceClass(true, false);
    final char[] password = generateUniquePassword();

    // (ironically,) set up an authenticatable resource with resource class create permission
    final Resource authenticatedResource = generateResourceAndAuthenticate();
    final String permissionName = generateResourceClassPermission(resourceClassName);
    final ResourcePermission grantedResourcePermission =
        ResourcePermissions.getInstance(permissionName);
    grantResourceCreatePermission(
        authenticatedResource, resourceClassName, domainName, permissionName);

    Set<Resource> resourcesByPermission =
        accessControlContext.getResourcesByResourcePermissions(
            authenticatedResource, resourceClassName, grantedResourcePermission);
    assertThat(resourcesByPermission.isEmpty(), is(true));

    // create resource with white-spaced names (and pwd) and verify
    final String domainName_whitespaced = " " + domainName + "\t";
    final String resourceClassName_whitespaced = " " + resourceClassName + "\t";
    final char[] password_whitespaced = (" " + password + "\t").toCharArray();
    final Resource whitespacedResource =
        accessControlContext.createResource(
            resourceClassName_whitespaced,
            domainName_whitespaced,
            PasswordCredentials.newInstance(password));

    assertThat(whitespacedResource, is(not(nullValue())));
    resourcesByPermission =
        accessControlContext.getResourcesByResourcePermissions(
            authenticatedResource, resourceClassName, grantedResourcePermission);
    assertThat(resourcesByPermission.size(), is(1));
    assertThat(accessControlContext.getDomainNameByResource(whitespacedResource), is(domainName));

    // create another resource WITHOUT white-spaced names and pwd
    final Resource resource =
        accessControlContext.createResource(
            resourceClassName, domainName, PasswordCredentials.newInstance(password));

    assertThat(resource, is(not(nullValue())));
    resourcesByPermission =
        accessControlContext.getResourcesByResourcePermissions(
            authenticatedResource, resourceClassName, grantedResourcePermission);
    assertThat(resourcesByPermission.size(), is(2));
    assertThat(resource.getId(), is(not(whitespacedResource.getId())));
    assertThat(accessControlContext.getDomainNameByResource(resource), is(domainName));

    // verify passwords are whitespace-sensitive
    accessControlContext.authenticate(
        whitespacedResource, PasswordCredentials.newInstance(password));
    accessControlContext.authenticate(resource, PasswordCredentials.newInstance(password));
    try {
      accessControlContext.authenticate(
          whitespacedResource, PasswordCredentials.newInstance(password_whitespaced));
      fail(
          "authentication of resource with extra leading/trailing password should not have succeeded");
    } catch (IncorrectCredentialsException e) {
      assertThat(e.getMessage().toLowerCase(), containsString("invalid password"));
    }
    try {
      accessControlContext.authenticate(
          resource, PasswordCredentials.newInstance(password_whitespaced));
      fail(
          "authentication of resource with extra leading/trailing password should not have succeeded");
    } catch (IncorrectCredentialsException e) {
      assertThat(e.getMessage().toLowerCase(), containsString("invalid password"));
    }

    // verify we can authenticate
    accessControlContext.authenticate(resource, PasswordCredentials.newInstance(password));
    accessControlContext.authenticate(
        whitespacedResource, PasswordCredentials.newInstance(password));
  }