diff --git a/spring/spring-data/pom.xml b/spring/spring-data/pom.xml index 897c14c3d3..43bc8b8c95 100644 --- a/spring/spring-data/pom.xml +++ b/spring/spring-data/pom.xml @@ -35,6 +35,10 @@ io.quarkus quarkus-hibernate-validator + + io.quarkus + quarkus-elytron-security-properties-file + io.quarkus.qe quarkus-test-service-database diff --git a/spring/spring-data/src/main/java/io/quarkus/ts/spring/data/rest/secured/DenyAllRepository.java b/spring/spring-data/src/main/java/io/quarkus/ts/spring/data/rest/secured/DenyAllRepository.java new file mode 100644 index 0000000000..d8a17af99b --- /dev/null +++ b/spring/spring-data/src/main/java/io/quarkus/ts/spring/data/rest/secured/DenyAllRepository.java @@ -0,0 +1,27 @@ +package io.quarkus.ts.spring.data.rest.secured; + +import java.util.Optional; + +import javax.annotation.security.DenyAll; +import javax.annotation.security.PermitAll; +import javax.annotation.security.RolesAllowed; + +import org.springframework.data.repository.CrudRepository; +import org.springframework.data.rest.core.annotation.RepositoryRestResource; +import org.springframework.data.rest.core.annotation.RestResource; + +import io.quarkus.ts.spring.data.rest.Library; + +@RepositoryRestResource(path = "/secured/deny-all") +@DenyAll +public interface DenyAllRepository extends CrudRepository { + @Override + @RestResource + @PermitAll + Iterable findAll(); + + @Override + @RestResource + @RolesAllowed("admin") + Optional findById(Long aLong); +} diff --git a/spring/spring-data/src/main/java/io/quarkus/ts/spring/data/rest/secured/PermitAllRepository.java b/spring/spring-data/src/main/java/io/quarkus/ts/spring/data/rest/secured/PermitAllRepository.java new file mode 100644 index 0000000000..c5cfdac3a7 --- /dev/null +++ b/spring/spring-data/src/main/java/io/quarkus/ts/spring/data/rest/secured/PermitAllRepository.java @@ -0,0 +1,21 @@ +package io.quarkus.ts.spring.data.rest.secured; + +import javax.annotation.security.DenyAll; +import javax.annotation.security.PermitAll; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.rest.core.annotation.RepositoryRestResource; +import org.springframework.data.rest.core.annotation.RestResource; + +import io.quarkus.ts.spring.data.rest.Library; + +@RepositoryRestResource(path = "/secured/permit-all") +@PermitAll +public interface PermitAllRepository extends JpaRepository { + @Override + @RestResource + @DenyAll + Page findAll(Pageable pageable); +} diff --git a/spring/spring-data/src/main/java/io/quarkus/ts/spring/data/rest/secured/PublicRepository.java b/spring/spring-data/src/main/java/io/quarkus/ts/spring/data/rest/secured/PublicRepository.java new file mode 100644 index 0000000000..d6235a84b1 --- /dev/null +++ b/spring/spring-data/src/main/java/io/quarkus/ts/spring/data/rest/secured/PublicRepository.java @@ -0,0 +1,19 @@ +package io.quarkus.ts.spring.data.rest.secured; + +import javax.annotation.security.DenyAll; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.repository.PagingAndSortingRepository; +import org.springframework.data.rest.core.annotation.RepositoryRestResource; +import org.springframework.data.rest.core.annotation.RestResource; + +import io.quarkus.ts.spring.data.rest.Library; + +@RepositoryRestResource(path = "/secured/public") +public interface PublicRepository extends PagingAndSortingRepository { + @Override + @RestResource + @DenyAll + Page findAll(Pageable pageable); +} diff --git a/spring/spring-data/src/main/java/io/quarkus/ts/spring/data/rest/secured/RolesAllowedRepository.java b/spring/spring-data/src/main/java/io/quarkus/ts/spring/data/rest/secured/RolesAllowedRepository.java new file mode 100644 index 0000000000..ac48136014 --- /dev/null +++ b/spring/spring-data/src/main/java/io/quarkus/ts/spring/data/rest/secured/RolesAllowedRepository.java @@ -0,0 +1,17 @@ +package io.quarkus.ts.spring.data.rest.secured; + +import javax.annotation.security.PermitAll; +import javax.annotation.security.RolesAllowed; + +import org.springframework.data.repository.CrudRepository; +import org.springframework.data.rest.core.annotation.RepositoryRestResource; + +import io.quarkus.ts.spring.data.rest.Library; + +@RepositoryRestResource(path = "/secured/roles-allowed") +@RolesAllowed("admin") +public interface RolesAllowedRepository extends CrudRepository { + @Override + @PermitAll + Iterable findAll(); +} diff --git a/spring/spring-data/src/main/resources/application.properties b/spring/spring-data/src/main/resources/application.properties index 1a9b6af43f..5ca59acbd6 100644 --- a/spring/spring-data/src/main/resources/application.properties +++ b/spring/spring-data/src/main/resources/application.properties @@ -1,3 +1,12 @@ quarkus.datasource.db-kind=postgresql quarkus.hibernate-orm.database.generation=drop-and-create quarkus.hibernate-orm.sql-load-script=import.sql + +# Basic security setup +quarkus.http.auth.basic=true +quarkus.security.users.embedded.enabled=true +quarkus.security.users.embedded.plain-text=true +quarkus.security.users.embedded.users.admin=admin +quarkus.security.users.embedded.users.user=user +quarkus.security.users.embedded.roles.admin=admin +quarkus.security.users.embedded.roles.user=user diff --git a/spring/spring-data/src/test/java/io/quarkus/ts/spring/data/rest/secured/OpenShiftSecuredRepositoryRestResourcesIT.java b/spring/spring-data/src/test/java/io/quarkus/ts/spring/data/rest/secured/OpenShiftSecuredRepositoryRestResourcesIT.java new file mode 100644 index 0000000000..e36f53ca01 --- /dev/null +++ b/spring/spring-data/src/test/java/io/quarkus/ts/spring/data/rest/secured/OpenShiftSecuredRepositoryRestResourcesIT.java @@ -0,0 +1,7 @@ +package io.quarkus.ts.spring.data.rest.secured; + +import io.quarkus.test.scenarios.OpenShiftScenario; + +@OpenShiftScenario +public class OpenShiftSecuredRepositoryRestResourcesIT extends SecuredRepositoryRestResourcesIT { +} diff --git a/spring/spring-data/src/test/java/io/quarkus/ts/spring/data/rest/secured/SecuredRepositoryRestResourcesIT.java b/spring/spring-data/src/test/java/io/quarkus/ts/spring/data/rest/secured/SecuredRepositoryRestResourcesIT.java new file mode 100644 index 0000000000..8439ebc97f --- /dev/null +++ b/spring/spring-data/src/test/java/io/quarkus/ts/spring/data/rest/secured/SecuredRepositoryRestResourcesIT.java @@ -0,0 +1,163 @@ +package io.quarkus.ts.spring.data.rest.secured; + +import static io.restassured.RestAssured.given; + +import org.apache.http.HttpStatus; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; + +import io.quarkus.test.scenarios.QuarkusScenario; +import io.quarkus.test.scenarios.annotations.DisabledOnQuarkusSnapshot; +import io.quarkus.test.scenarios.annotations.DisabledOnQuarkusVersion; +import io.quarkus.ts.spring.data.AbstractDbIT; +import io.restassured.http.ContentType; + +@Tag("QUARKUS-2788") +@QuarkusScenario +public class SecuredRepositoryRestResourcesIT extends AbstractDbIT { + private static final long NONEXISTENT_ENTITY_ID = 999; + private static final String BASE_URL = "/secured"; + + private String getUrl(String path) { + return BASE_URL + path; + } + + @Test + void publicResourceNoAuth() { + app.given() + .accept(ContentType.JSON) + .get(getUrl("/public/" + NONEXISTENT_ENTITY_ID)) + .then().statusCode(HttpStatus.SC_NOT_FOUND); + } + + @Test + void publicResourceDenyAllMethodNoAuth() { + app.given() + .accept(ContentType.JSON) + .get(getUrl("/public")) + .then().statusCode(HttpStatus.SC_UNAUTHORIZED); + } + + @Test + void publicResourceDenyAllMethodAuth() { + app.given() + .accept(ContentType.JSON) + .auth().basic("admin", "admin") + .get(getUrl("/public")) + .then().statusCode(HttpStatus.SC_FORBIDDEN); + } + + @Test + void denyAllResourceNoAuth() { + app.given() + .accept(ContentType.JSON) + .delete(getUrl("/deny-all/" + NONEXISTENT_ENTITY_ID)) + .then().statusCode(HttpStatus.SC_UNAUTHORIZED); + } + + @Test + void denyAllResourceAuth() { + app.given() + .accept(ContentType.JSON) + .auth().basic("admin", "admin") + .delete(getUrl("/deny-all/" + NONEXISTENT_ENTITY_ID)) + .then().statusCode(HttpStatus.SC_FORBIDDEN); + } + + @Test + void denyAllResourcePermitAllMethodNoAuth() { + given() + .accept(ContentType.JSON) + .get(getUrl("/deny-all")) + .then().statusCode(HttpStatus.SC_OK); + } + + @Test + void denyAllResourceRolesAllowedMethodNoAuth() { + app.given() + .accept(ContentType.JSON) + .get(getUrl("/deny-all/" + NONEXISTENT_ENTITY_ID)) + .then().statusCode(HttpStatus.SC_UNAUTHORIZED); + } + + @Test + void denyAllResourceRolesAllowedMethodAuthForbidden() { + app.given() + .accept(ContentType.JSON) + .auth().basic("user", "user") + .get(getUrl("/deny-all/" + NONEXISTENT_ENTITY_ID)) + .then().statusCode(HttpStatus.SC_FORBIDDEN); + } + + @Test + void denyAllResourceRolesAllowedMethodAuthPermitted() { + app.given() + .accept(ContentType.JSON) + .auth().basic("admin", "admin") + .get(getUrl("/deny-all/" + NONEXISTENT_ENTITY_ID)) + .then().statusCode(HttpStatus.SC_NOT_FOUND); + } + + @Test + void permitAllResourceNoAuth() { + app.given() + .accept(ContentType.JSON) + .get(getUrl("/permit-all/" + NONEXISTENT_ENTITY_ID)) + .then().statusCode(HttpStatus.SC_NOT_FOUND); + } + + @Test + void permitAllResourceDenyAllMethodNoAuth() { + app.given() + .accept(ContentType.JSON) + .get(getUrl("/permit-all")) + .then().statusCode(HttpStatus.SC_UNAUTHORIZED); + } + + @Test + void permitAllResourceDenyAllMethodAuth() { + app.given() + .accept(ContentType.JSON) + .auth().basic("admin", "admin") + .get(getUrl("/permit-all")) + .then().statusCode(HttpStatus.SC_FORBIDDEN); + } + + @Test + void rolesAllowedResourceNoAuth() { + app.given() + .accept(ContentType.JSON) + .get(getUrl("/roles-allowed")) + .then().statusCode(HttpStatus.SC_UNAUTHORIZED); + } + + @Test + void rolesAllowedResourceAuthForbidden() { + app.given() + .accept(ContentType.JSON) + .auth().basic("user", "user") + .get(getUrl("/roles-allowed")) + .then().statusCode(HttpStatus.SC_FORBIDDEN); + } + + @Test + void rolesAllowedResourceAuthPermitted() { + app.given() + .accept(ContentType.JSON) + .auth().basic("admin", "admin") + .get(getUrl("/roles-allowed")) + .then().statusCode(HttpStatus.SC_OK); + } + + // TODO: Enable for Quarkus SNAPSHOT after a fix for https://github.com/quarkusio/quarkus/issues/30358 is merged. + @DisabledOnQuarkusSnapshot(reason = "https://github.com/quarkusio/quarkus/issues/30358") + // TODO: Enable after a fix for https://github.com/quarkusio/quarkus/issues/30358 is backported to Quarkus 2.13, 2.14, 2.15 + @DisabledOnQuarkusVersion(version = "(2\\.13\\..*)|(2\\.14\\..*)|(2\\.15\\..*)", reason = "https://github.com/quarkusio/quarkus/issues/30358") + @Test + void rolesAllowedResourcePermitAllMethodWithoutRestResourceAnnotation() { + app.given() + .accept(ContentType.JSON) + .get(getUrl("/roles-allowed")) + .then().statusCode(HttpStatus.SC_OK); + } +} diff --git a/sql-db/panache-flyway/pom.xml b/sql-db/panache-flyway/pom.xml index 757a4c5fa5..069dec6cdb 100644 --- a/sql-db/panache-flyway/pom.xml +++ b/sql-db/panache-flyway/pom.xml @@ -35,6 +35,10 @@ io.quarkus quarkus-hibernate-validator + + io.quarkus + quarkus-elytron-security-properties-file + org.testcontainers mysql diff --git a/sql-db/panache-flyway/src/main/java/io/quarkus/ts/sqldb/panacheflyway/secured/EntityDenyAllResource.java b/sql-db/panache-flyway/src/main/java/io/quarkus/ts/sqldb/panacheflyway/secured/EntityDenyAllResource.java new file mode 100644 index 0000000000..2e9becb26c --- /dev/null +++ b/sql-db/panache-flyway/src/main/java/io/quarkus/ts/sqldb/panacheflyway/secured/EntityDenyAllResource.java @@ -0,0 +1,30 @@ +package io.quarkus.ts.sqldb.panacheflyway.secured; + +import java.util.List; + +import javax.annotation.security.DenyAll; +import javax.annotation.security.PermitAll; +import javax.annotation.security.RolesAllowed; + +import io.quarkus.hibernate.orm.rest.data.panache.PanacheEntityResource; +import io.quarkus.panache.common.Page; +import io.quarkus.panache.common.Sort; +import io.quarkus.rest.data.panache.MethodProperties; +import io.quarkus.rest.data.panache.ResourceProperties; +import io.quarkus.ts.sqldb.panacheflyway.ApplicationEntity; + +@ResourceProperties(path = "/secured/entity/deny-all") +@DenyAll +public interface EntityDenyAllResource extends PanacheEntityResource { + @Override + @PermitAll + long count(); + + @Override + @RolesAllowed("admin") + List list(Page page, Sort sort); + + @Override + @MethodProperties(rolesAllowed = "admin") + ApplicationEntity get(Long aLong); +} diff --git a/sql-db/panache-flyway/src/main/java/io/quarkus/ts/sqldb/panacheflyway/secured/EntityPermitAllResource.java b/sql-db/panache-flyway/src/main/java/io/quarkus/ts/sqldb/panacheflyway/secured/EntityPermitAllResource.java new file mode 100644 index 0000000000..3806acd616 --- /dev/null +++ b/sql-db/panache-flyway/src/main/java/io/quarkus/ts/sqldb/panacheflyway/secured/EntityPermitAllResource.java @@ -0,0 +1,16 @@ +package io.quarkus.ts.sqldb.panacheflyway.secured; + +import javax.annotation.security.DenyAll; +import javax.annotation.security.PermitAll; + +import io.quarkus.hibernate.orm.rest.data.panache.PanacheEntityResource; +import io.quarkus.rest.data.panache.ResourceProperties; +import io.quarkus.ts.sqldb.panacheflyway.ApplicationEntity; + +@ResourceProperties(path = "/secured/entity/permit-all") +@PermitAll +public interface EntityPermitAllResource extends PanacheEntityResource { + @Override + @DenyAll + long count(); +} diff --git a/sql-db/panache-flyway/src/main/java/io/quarkus/ts/sqldb/panacheflyway/secured/EntityPublicResource.java b/sql-db/panache-flyway/src/main/java/io/quarkus/ts/sqldb/panacheflyway/secured/EntityPublicResource.java new file mode 100644 index 0000000000..9dbf396410 --- /dev/null +++ b/sql-db/panache-flyway/src/main/java/io/quarkus/ts/sqldb/panacheflyway/secured/EntityPublicResource.java @@ -0,0 +1,14 @@ +package io.quarkus.ts.sqldb.panacheflyway.secured; + +import javax.annotation.security.DenyAll; + +import io.quarkus.hibernate.orm.rest.data.panache.PanacheEntityResource; +import io.quarkus.rest.data.panache.ResourceProperties; +import io.quarkus.ts.sqldb.panacheflyway.ApplicationEntity; + +@ResourceProperties(path = "/secured/entity/public") +public interface EntityPublicResource extends PanacheEntityResource { + @Override + @DenyAll + long count(); +} diff --git a/sql-db/panache-flyway/src/main/java/io/quarkus/ts/sqldb/panacheflyway/secured/EntityResourcePropertiesRolesAllowedResource.java b/sql-db/panache-flyway/src/main/java/io/quarkus/ts/sqldb/panacheflyway/secured/EntityResourcePropertiesRolesAllowedResource.java new file mode 100644 index 0000000000..5f6ec25b85 --- /dev/null +++ b/sql-db/panache-flyway/src/main/java/io/quarkus/ts/sqldb/panacheflyway/secured/EntityResourcePropertiesRolesAllowedResource.java @@ -0,0 +1,9 @@ +package io.quarkus.ts.sqldb.panacheflyway.secured; + +import io.quarkus.hibernate.orm.rest.data.panache.PanacheEntityResource; +import io.quarkus.rest.data.panache.ResourceProperties; +import io.quarkus.ts.sqldb.panacheflyway.ApplicationEntity; + +@ResourceProperties(path = "/secured/entity/resource-properties-roles-allowed", rolesAllowed = "admin") +public interface EntityResourcePropertiesRolesAllowedResource extends PanacheEntityResource { +} diff --git a/sql-db/panache-flyway/src/main/java/io/quarkus/ts/sqldb/panacheflyway/secured/EntityRolesAllowedResource.java b/sql-db/panache-flyway/src/main/java/io/quarkus/ts/sqldb/panacheflyway/secured/EntityRolesAllowedResource.java new file mode 100644 index 0000000000..d0141681f1 --- /dev/null +++ b/sql-db/panache-flyway/src/main/java/io/quarkus/ts/sqldb/panacheflyway/secured/EntityRolesAllowedResource.java @@ -0,0 +1,12 @@ +package io.quarkus.ts.sqldb.panacheflyway.secured; + +import javax.annotation.security.RolesAllowed; + +import io.quarkus.hibernate.orm.rest.data.panache.PanacheEntityResource; +import io.quarkus.rest.data.panache.ResourceProperties; +import io.quarkus.ts.sqldb.panacheflyway.ApplicationEntity; + +@ResourceProperties(path = "/secured/entity/roles-allowed") +@RolesAllowed("admin") +public interface EntityRolesAllowedResource extends PanacheEntityResource { +} diff --git a/sql-db/panache-flyway/src/main/java/io/quarkus/ts/sqldb/panacheflyway/secured/RepositoryDenyAllResource.java b/sql-db/panache-flyway/src/main/java/io/quarkus/ts/sqldb/panacheflyway/secured/RepositoryDenyAllResource.java new file mode 100644 index 0000000000..ee2256d194 --- /dev/null +++ b/sql-db/panache-flyway/src/main/java/io/quarkus/ts/sqldb/panacheflyway/secured/RepositoryDenyAllResource.java @@ -0,0 +1,31 @@ +package io.quarkus.ts.sqldb.panacheflyway.secured; + +import java.util.List; + +import javax.annotation.security.DenyAll; +import javax.annotation.security.PermitAll; +import javax.annotation.security.RolesAllowed; + +import io.quarkus.hibernate.orm.rest.data.panache.PanacheRepositoryResource; +import io.quarkus.panache.common.Page; +import io.quarkus.panache.common.Sort; +import io.quarkus.rest.data.panache.MethodProperties; +import io.quarkus.rest.data.panache.ResourceProperties; +import io.quarkus.ts.sqldb.panacheflyway.UserEntity; +import io.quarkus.ts.sqldb.panacheflyway.UserRepository; + +@ResourceProperties(path = "/secured/repository/deny-all") +@DenyAll +public interface RepositoryDenyAllResource extends PanacheRepositoryResource { + @Override + @PermitAll + long count(); + + @Override + @RolesAllowed("admin") + List list(Page page, Sort sort); + + @Override + @MethodProperties(rolesAllowed = "admin") + UserEntity get(Long aLong); +} diff --git a/sql-db/panache-flyway/src/main/java/io/quarkus/ts/sqldb/panacheflyway/secured/RepositoryPermitAllResource.java b/sql-db/panache-flyway/src/main/java/io/quarkus/ts/sqldb/panacheflyway/secured/RepositoryPermitAllResource.java new file mode 100644 index 0000000000..6cd3dbd932 --- /dev/null +++ b/sql-db/panache-flyway/src/main/java/io/quarkus/ts/sqldb/panacheflyway/secured/RepositoryPermitAllResource.java @@ -0,0 +1,17 @@ +package io.quarkus.ts.sqldb.panacheflyway.secured; + +import javax.annotation.security.DenyAll; +import javax.annotation.security.PermitAll; + +import io.quarkus.hibernate.orm.rest.data.panache.PanacheRepositoryResource; +import io.quarkus.rest.data.panache.ResourceProperties; +import io.quarkus.ts.sqldb.panacheflyway.UserEntity; +import io.quarkus.ts.sqldb.panacheflyway.UserRepository; + +@ResourceProperties(path = "/secured/repository/permit-all") +@PermitAll +public interface RepositoryPermitAllResource extends PanacheRepositoryResource { + @Override + @DenyAll + long count(); +} diff --git a/sql-db/panache-flyway/src/main/java/io/quarkus/ts/sqldb/panacheflyway/secured/RepositoryPublicResource.java b/sql-db/panache-flyway/src/main/java/io/quarkus/ts/sqldb/panacheflyway/secured/RepositoryPublicResource.java new file mode 100644 index 0000000000..c88bd054db --- /dev/null +++ b/sql-db/panache-flyway/src/main/java/io/quarkus/ts/sqldb/panacheflyway/secured/RepositoryPublicResource.java @@ -0,0 +1,15 @@ +package io.quarkus.ts.sqldb.panacheflyway.secured; + +import javax.annotation.security.DenyAll; + +import io.quarkus.hibernate.orm.rest.data.panache.PanacheRepositoryResource; +import io.quarkus.rest.data.panache.ResourceProperties; +import io.quarkus.ts.sqldb.panacheflyway.UserEntity; +import io.quarkus.ts.sqldb.panacheflyway.UserRepository; + +@ResourceProperties(path = "/secured/repository/public") +public interface RepositoryPublicResource extends PanacheRepositoryResource { + @Override + @DenyAll + long count(); +} diff --git a/sql-db/panache-flyway/src/main/java/io/quarkus/ts/sqldb/panacheflyway/secured/RepositoryResourcePropertiesRolesAllowedResource.java b/sql-db/panache-flyway/src/main/java/io/quarkus/ts/sqldb/panacheflyway/secured/RepositoryResourcePropertiesRolesAllowedResource.java new file mode 100644 index 0000000000..a0a8b5a5b4 --- /dev/null +++ b/sql-db/panache-flyway/src/main/java/io/quarkus/ts/sqldb/panacheflyway/secured/RepositoryResourcePropertiesRolesAllowedResource.java @@ -0,0 +1,11 @@ +package io.quarkus.ts.sqldb.panacheflyway.secured; + +import io.quarkus.hibernate.orm.rest.data.panache.PanacheRepositoryResource; +import io.quarkus.rest.data.panache.ResourceProperties; +import io.quarkus.ts.sqldb.panacheflyway.UserEntity; +import io.quarkus.ts.sqldb.panacheflyway.UserRepository; + +@ResourceProperties(path = "/secured/repository/resource-properties-roles-allowed", rolesAllowed = "admin") +public interface RepositoryResourcePropertiesRolesAllowedResource + extends PanacheRepositoryResource { +} diff --git a/sql-db/panache-flyway/src/main/java/io/quarkus/ts/sqldb/panacheflyway/secured/RepositoryRolesAllowedResource.java b/sql-db/panache-flyway/src/main/java/io/quarkus/ts/sqldb/panacheflyway/secured/RepositoryRolesAllowedResource.java new file mode 100644 index 0000000000..a2c0da618c --- /dev/null +++ b/sql-db/panache-flyway/src/main/java/io/quarkus/ts/sqldb/panacheflyway/secured/RepositoryRolesAllowedResource.java @@ -0,0 +1,13 @@ +package io.quarkus.ts.sqldb.panacheflyway.secured; + +import javax.annotation.security.RolesAllowed; + +import io.quarkus.hibernate.orm.rest.data.panache.PanacheRepositoryResource; +import io.quarkus.rest.data.panache.ResourceProperties; +import io.quarkus.ts.sqldb.panacheflyway.UserEntity; +import io.quarkus.ts.sqldb.panacheflyway.UserRepository; + +@ResourceProperties(path = "/secured/repository/roles-allowed") +@RolesAllowed("admin") +public interface RepositoryRolesAllowedResource extends PanacheRepositoryResource { +} diff --git a/sql-db/panache-flyway/src/main/resources/application.properties b/sql-db/panache-flyway/src/main/resources/application.properties index 3164cab32b..3409020b56 100644 --- a/sql-db/panache-flyway/src/main/resources/application.properties +++ b/sql-db/panache-flyway/src/main/resources/application.properties @@ -30,3 +30,12 @@ quarkus.flyway.schemas=test %agroal_pool_test.quarkus.datasource.jdbc.acquisition-timeout=60S %agroal_pool_test.quarkus.datasource.jdbc.validation-query-sql=SELECT CURRENT_TIMESTAMP %agroal_pool_test.quarkus.datasource.jdbc.new-connection-sql=SELECT CURRENT_TIMESTAMP + +# Basic security setup +quarkus.http.auth.basic=true +quarkus.security.users.embedded.enabled=true +quarkus.security.users.embedded.plain-text=true +quarkus.security.users.embedded.users.admin=admin +quarkus.security.users.embedded.users.user=user +quarkus.security.users.embedded.roles.admin=admin +quarkus.security.users.embedded.roles.user=user diff --git a/sql-db/panache-flyway/src/test/java/io/quarkus/ts/sqldb/panacheflyway/secured/AbstractSecuredPanacheResourceIT.java b/sql-db/panache-flyway/src/test/java/io/quarkus/ts/sqldb/panacheflyway/secured/AbstractSecuredPanacheResourceIT.java new file mode 100644 index 0000000000..6606170105 --- /dev/null +++ b/sql-db/panache-flyway/src/test/java/io/quarkus/ts/sqldb/panacheflyway/secured/AbstractSecuredPanacheResourceIT.java @@ -0,0 +1,176 @@ +package io.quarkus.ts.sqldb.panacheflyway.secured; + +import static io.restassured.RestAssured.given; + +import org.apache.http.HttpStatus; +import org.junit.jupiter.api.Test; + +import io.quarkus.ts.sqldb.panacheflyway.PanacheWithFlywayBaseIT; + +public abstract class AbstractSecuredPanacheResourceIT extends PanacheWithFlywayBaseIT { + private static final long NONEXISTENT_ENTITY_ID = 999; + + protected abstract String getBaseUrl(); + + private String getUrl(String path) { + return getBaseUrl() + path; + } + + @Test + void publicResourceNoAuth() { + given() + .get(getUrl("/public")) + .then().statusCode(HttpStatus.SC_OK); + } + + @Test + void publicResourceDenyAllMethodNoAuth() { + given() + .get(getUrl("/public/count")) + .then().statusCode(HttpStatus.SC_UNAUTHORIZED); + } + + @Test + void publicResourceDenyAllMethodAuth() { + given() + .auth().basic("admin", "admin") + .get(getUrl("/public/count")) + .then().statusCode(HttpStatus.SC_FORBIDDEN); + } + + @Test + void denyAllResourceNoAuth() { + given() + .delete(getUrl("/deny-all/" + NONEXISTENT_ENTITY_ID)) + .then().statusCode(HttpStatus.SC_UNAUTHORIZED); + } + + @Test + void denyAllResourceAuth() { + given() + .auth().basic("admin", "admin") + .delete(getUrl("/deny-all/" + NONEXISTENT_ENTITY_ID)) + .then().statusCode(HttpStatus.SC_FORBIDDEN); + } + + @Test + void denyAllResourcePermitAllMethodNoAuth() { + given() + .get(getUrl("/deny-all/count")) + .then().statusCode(HttpStatus.SC_OK); + } + + @Test + void denyAllResourceRolesAllowedMethodNoAuth() { + given() + .get(getUrl("/deny-all")) + .then().statusCode(HttpStatus.SC_UNAUTHORIZED); + } + + @Test + void denyAllResourceRolesAllowedMethodAuthForbidden() { + given() + .auth().basic("user", "user") + .get(getUrl("/deny-all")) + .then().statusCode(HttpStatus.SC_FORBIDDEN); + } + + @Test + void denyAllResourceRolesAllowedMethodAuthPermitted() { + given() + .auth().basic("admin", "admin") + .get(getUrl("/deny-all")) + .then().statusCode(HttpStatus.SC_OK); + } + + @Test + void denyAllResourcePropertiesRolesAllowedMethodNoAuth() { + given() + .get(getUrl("/deny-all/" + NONEXISTENT_ENTITY_ID)) + .then().statusCode(HttpStatus.SC_UNAUTHORIZED); + } + + @Test + void denyAllResourcePropertiesRolesAllowedMethodAuthForbidden() { + given() + .auth().basic("user", "user") + .get(getUrl("/deny-all/" + NONEXISTENT_ENTITY_ID)) + .then().statusCode(HttpStatus.SC_FORBIDDEN); + } + + @Test + void denyAllResourcePropertiesRolesAllowedMethodAuthPermitted() { + given() + .auth().basic("admin", "admin") + .get(getUrl("/deny-all/" + NONEXISTENT_ENTITY_ID)) + .then().statusCode(HttpStatus.SC_NOT_FOUND); + } + + @Test + void permitAllResourceNoAuth() { + given() + .get(getUrl("/permit-all")) + .then().statusCode(HttpStatus.SC_OK); + } + + @Test + void permitAllResourceDenyAllMethodNoAuth() { + given() + .get(getUrl("/permit-all/count")) + .then().statusCode(HttpStatus.SC_UNAUTHORIZED); + } + + @Test + void permitAllResourceDenyAllMethodAuth() { + given() + .auth().basic("admin", "admin") + .get(getUrl("/permit-all/count")) + .then().statusCode(HttpStatus.SC_FORBIDDEN); + } + + @Test + void propertiesRolesAllowedResourceNoAuth() { + given() + .get(getUrl("/resource-properties-roles-allowed")) + .then().statusCode(HttpStatus.SC_UNAUTHORIZED); + } + + @Test + void propertiesRolesAllowedResourceAuthForbidden() { + given() + .auth().basic("user", "user") + .get(getUrl("/resource-properties-roles-allowed")) + .then().statusCode(HttpStatus.SC_FORBIDDEN); + } + + @Test + void propertiesRolesAllowedResourceAuthPermitted() { + given() + .auth().basic("admin", "admin") + .get(getUrl("/resource-properties-roles-allowed")) + .then().statusCode(HttpStatus.SC_OK); + } + + @Test + void rolesAllowedResourceNoAuth() { + given() + .get(getUrl("/roles-allowed")) + .then().statusCode(HttpStatus.SC_UNAUTHORIZED); + } + + @Test + void rolesAllowedResourceAuthForbidden() { + given() + .auth().basic("user", "user") + .get(getUrl("/roles-allowed")) + .then().statusCode(HttpStatus.SC_FORBIDDEN); + } + + @Test + void rolesAllowedResourceAuthPermitted() { + given() + .auth().basic("admin", "admin") + .get(getUrl("/roles-allowed")) + .then().statusCode(HttpStatus.SC_OK); + } +} diff --git a/sql-db/panache-flyway/src/test/java/io/quarkus/ts/sqldb/panacheflyway/secured/OpenShiftSecuredPanacheEntityResourceIT.java b/sql-db/panache-flyway/src/test/java/io/quarkus/ts/sqldb/panacheflyway/secured/OpenShiftSecuredPanacheEntityResourceIT.java new file mode 100644 index 0000000000..fc555a7a9d --- /dev/null +++ b/sql-db/panache-flyway/src/test/java/io/quarkus/ts/sqldb/panacheflyway/secured/OpenShiftSecuredPanacheEntityResourceIT.java @@ -0,0 +1,7 @@ +package io.quarkus.ts.sqldb.panacheflyway.secured; + +import io.quarkus.test.scenarios.OpenShiftScenario; + +@OpenShiftScenario +public class OpenShiftSecuredPanacheEntityResourceIT extends SecuredPanacheEntityResourceIT { +} diff --git a/sql-db/panache-flyway/src/test/java/io/quarkus/ts/sqldb/panacheflyway/secured/OpenShiftSecuredPanacheRepositoryResourceIT.java b/sql-db/panache-flyway/src/test/java/io/quarkus/ts/sqldb/panacheflyway/secured/OpenShiftSecuredPanacheRepositoryResourceIT.java new file mode 100644 index 0000000000..1ce44a2697 --- /dev/null +++ b/sql-db/panache-flyway/src/test/java/io/quarkus/ts/sqldb/panacheflyway/secured/OpenShiftSecuredPanacheRepositoryResourceIT.java @@ -0,0 +1,7 @@ +package io.quarkus.ts.sqldb.panacheflyway.secured; + +import io.quarkus.test.scenarios.OpenShiftScenario; + +@OpenShiftScenario +public class OpenShiftSecuredPanacheRepositoryResourceIT extends SecuredPanacheRepositoryResourceIT { +} diff --git a/sql-db/panache-flyway/src/test/java/io/quarkus/ts/sqldb/panacheflyway/secured/SecuredPanacheEntityResourceIT.java b/sql-db/panache-flyway/src/test/java/io/quarkus/ts/sqldb/panacheflyway/secured/SecuredPanacheEntityResourceIT.java new file mode 100644 index 0000000000..d588da07c6 --- /dev/null +++ b/sql-db/panache-flyway/src/test/java/io/quarkus/ts/sqldb/panacheflyway/secured/SecuredPanacheEntityResourceIT.java @@ -0,0 +1,16 @@ +package io.quarkus.ts.sqldb.panacheflyway.secured; + +import org.junit.jupiter.api.Tag; + +import io.quarkus.test.scenarios.QuarkusScenario; + +@Tag("QUARKUS-2788") +@QuarkusScenario +public class SecuredPanacheEntityResourceIT extends AbstractSecuredPanacheResourceIT { + private static final String BASE_URL = "/secured/entity"; + + @Override + protected String getBaseUrl() { + return BASE_URL; + } +} diff --git a/sql-db/panache-flyway/src/test/java/io/quarkus/ts/sqldb/panacheflyway/secured/SecuredPanacheRepositoryResourceIT.java b/sql-db/panache-flyway/src/test/java/io/quarkus/ts/sqldb/panacheflyway/secured/SecuredPanacheRepositoryResourceIT.java new file mode 100644 index 0000000000..16f2bb543b --- /dev/null +++ b/sql-db/panache-flyway/src/test/java/io/quarkus/ts/sqldb/panacheflyway/secured/SecuredPanacheRepositoryResourceIT.java @@ -0,0 +1,16 @@ +package io.quarkus.ts.sqldb.panacheflyway.secured; + +import org.junit.jupiter.api.Tag; + +import io.quarkus.test.scenarios.QuarkusScenario; + +@Tag("QUARKUS-2788") +@QuarkusScenario +public class SecuredPanacheRepositoryResourceIT extends AbstractSecuredPanacheResourceIT { + private static final String BASE_URL = "/secured/repository"; + + @Override + protected String getBaseUrl() { + return BASE_URL; + } +}