From 5fc2e36ad06cb2bec3f2064c7e9e163e7c007742 Mon Sep 17 00:00:00 2001 From: Andrej Petras Date: Thu, 11 Jan 2024 20:05:20 +0100 Subject: [PATCH] feat: add user permissions --- .../permission/common/models/TokenConfig.java | 27 ++++ .../common/services/TokenService.java | 144 ++++++++++++++++++ .../permission/domain/daos/PermissionDAO.java | 27 +++- .../permission/domain/models/Assignment.java | 2 + .../permission/domain/models/Permission.java | 9 +- .../onecx/permission/domain/models/Role.java | 7 +- .../controllers/PermissionRestController.java | 45 ++++++ .../external/v1/mappers/PermissionMapper.java | 30 ++++ .../controllers/PermissionRestController.java | 29 ---- src/main/openapi/onecx-permission-v1.yaml | 48 +++--- src/main/resources/application.properties | 9 ++ .../db/v1/2024-01-04-create-tables.xml | 9 ++ .../domain/daos/PermissionDAOTest.java | 2 + .../v1/PermissionRestControllerTest.java | 38 +++++ .../v1/PermissionRestControllerTestIT.java | 8 + .../onecx/permission/test/AbstractTest.java | 19 ++- src/test/resources/data/test-v1.xml | 13 ++ 17 files changed, 407 insertions(+), 59 deletions(-) create mode 100644 src/main/java/io/github/onecx/permission/common/models/TokenConfig.java create mode 100644 src/main/java/io/github/onecx/permission/common/services/TokenService.java create mode 100644 src/main/java/io/github/onecx/permission/rs/external/v1/controllers/PermissionRestController.java create mode 100644 src/main/java/io/github/onecx/permission/rs/external/v1/mappers/PermissionMapper.java delete mode 100644 src/main/java/io/github/onecx/permission/rs/v1/controllers/PermissionRestController.java create mode 100644 src/test/java/io/github/onecx/permission/rs/external/v1/PermissionRestControllerTest.java create mode 100644 src/test/java/io/github/onecx/permission/rs/external/v1/PermissionRestControllerTestIT.java diff --git a/src/main/java/io/github/onecx/permission/common/models/TokenConfig.java b/src/main/java/io/github/onecx/permission/common/models/TokenConfig.java new file mode 100644 index 0000000..c52ab98 --- /dev/null +++ b/src/main/java/io/github/onecx/permission/common/models/TokenConfig.java @@ -0,0 +1,27 @@ +package io.github.onecx.permission.common.models; + +import java.util.Optional; + +import io.smallrye.config.ConfigMapping; +import io.smallrye.config.WithDefault; +import io.smallrye.config.WithName; + +@ConfigMapping(prefix = "onecx.permission") +public interface TokenConfig { + + @WithName("token.verified") + boolean tokenVerified(); + + @WithName("token.issuer.public-key-location.suffix") + String tokenPublicKeyLocationSuffix(); + + @WithName("token.issuer.public-key-location.enabled") + boolean tokenPublicKeyEnabled(); + + @WithName("token.claim.separator") + Optional tokenClaimSeparator(); + + @WithName("token.claim.path") + @WithDefault("realm_access.roles") + String tokenClaimPath(); +} diff --git a/src/main/java/io/github/onecx/permission/common/services/TokenService.java b/src/main/java/io/github/onecx/permission/common/services/TokenService.java new file mode 100644 index 0000000..9f4fa1b --- /dev/null +++ b/src/main/java/io/github/onecx/permission/common/services/TokenService.java @@ -0,0 +1,144 @@ +package io.github.onecx.permission.common.services; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.regex.Pattern; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; +import jakarta.json.JsonArray; +import jakarta.json.JsonObject; + +import org.jose4j.jws.JsonWebSignature; +import org.jose4j.jwt.JwtClaims; +import org.jose4j.jwt.MalformedClaimException; +import org.jose4j.jwt.consumer.InvalidJwtException; +import org.jose4j.jwx.JsonWebStructure; +import org.jose4j.lang.JoseException; + +import io.github.onecx.permission.common.models.TokenConfig; +import io.smallrye.jwt.auth.principal.JWTAuthContextInfo; +import io.smallrye.jwt.auth.principal.JWTParser; +import io.smallrye.jwt.auth.principal.ParseException; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@ApplicationScoped +public class TokenService { + + private static final Pattern CLAIM_PATH_PATTERN = Pattern.compile("\\/(?=(?:(?:[^\"]*\"){2})*[^\"]*$)"); + + @Inject + JWTAuthContextInfo authContextInfo; + + @Inject + TokenConfig config; + + @Inject + JWTParser parser; + + public List getTokenRoles(String tokenData) { + try { + return getRoles(tokenData); + } catch (Exception ex) { + throw new TokenException("Error parsing principal token", ex); + } + } + + private List getRoles(String tokenData) + throws JoseException, InvalidJwtException, MalformedClaimException, ParseException { + + if (config.tokenVerified()) { + var info = authContextInfo; + + // get public key location from issuer URL + if (config.tokenPublicKeyEnabled()) { + var jws = (JsonWebSignature) JsonWebStructure.fromCompactSerialization(tokenData); + var jwtClaims = JwtClaims.parse(jws.getUnverifiedPayload()); + var publicKeyLocation = jwtClaims.getIssuer() + config.tokenPublicKeyLocationSuffix(); + info = new JWTAuthContextInfo(authContextInfo); + info.setPublicKeyLocation(publicKeyLocation); + + } + + info.setVerifyCertificateThumbprint(false); + var token = parser.parse(tokenData, info); + + // return findClaimWithRoles(config, token); + return List.of(); + + } else { + + var jws = (JsonWebSignature) JsonWebStructure.fromCompactSerialization(tokenData); + var jwtClaims = JwtClaims.parse(jws.getUnverifiedPayload()); + List list = (List) jwtClaims.flattenClaims().get(config.tokenClaimPath()); + return (List) list; + // jwtClaims.flattenClaims() + // return findClaimWithRoles(config, jwtClaims); + // return List.of(); + } + } + + private static List findClaimWithRoles(TokenConfig tokenConfig, JsonObject json) { + + var path = tokenConfig.tokenClaimPath(); + Object claimValue = findClaimValue(path, json, splitClaimPath(path), 0); + + if (claimValue instanceof JsonArray) { + return convertJsonArrayToList((JsonArray) claimValue); + } else if (claimValue != null) { + String sep = tokenConfig.tokenClaimSeparator().isPresent() ? tokenConfig.tokenClaimSeparator().get() : " "; + if (claimValue.toString().isBlank()) { + return Collections.emptyList(); + } + return Arrays.asList(claimValue.toString().split(sep)); + } else { + return Collections.emptyList(); + } + } + + private static List convertJsonArrayToList(JsonArray claimValue) { + List list = new ArrayList<>(claimValue.size()); + for (int i = 0; i < claimValue.size(); i++) { + String claimValueStr = claimValue.getString(i); + if (claimValueStr == null || claimValueStr.isBlank()) { + continue; + } + list.add(claimValue.getString(i)); + } + return list; + } + + private static String[] splitClaimPath(String claimPath) { + return claimPath.indexOf('/') > 0 ? CLAIM_PATH_PATTERN.split(claimPath) : new String[] { claimPath }; + } + + private static Object findClaimValue(String claimPath, JsonObject json, String[] pathArray, int step) { + Object claimValue = json.getValue(pathArray[step].replace("\"", "")); + if (claimValue == null) { + log.debug("No claim exists at the path '{}' at the path segment '{}'", claimPath, pathArray[step]); + } else if (step + 1 < pathArray.length) { + if (claimValue instanceof JsonObject) { + int nextStep = step + 1; + return findClaimValue(claimPath, (JsonObject) claimValue, pathArray, nextStep); + } else { + log.debug("Claim value at the path '{}' is not a json object", claimPath); + } + } + + return claimValue; + } + + public static class TokenException extends RuntimeException { + + public TokenException(String message) { + super(message); + } + + public TokenException(String message, Throwable t) { + super(message, t); + } + } +} diff --git a/src/main/java/io/github/onecx/permission/domain/daos/PermissionDAO.java b/src/main/java/io/github/onecx/permission/domain/daos/PermissionDAO.java index e6dff4b..19dc376 100644 --- a/src/main/java/io/github/onecx/permission/domain/daos/PermissionDAO.java +++ b/src/main/java/io/github/onecx/permission/domain/daos/PermissionDAO.java @@ -5,6 +5,7 @@ import jakarta.enterprise.context.ApplicationScoped; import jakarta.persistence.criteria.Predicate; +import jakarta.persistence.criteria.Subquery; import jakarta.transaction.Transactional; import org.tkit.quarkus.jpa.daos.AbstractDAO; @@ -14,8 +15,7 @@ import org.tkit.quarkus.jpa.utils.QueryCriteriaUtil; import io.github.onecx.permission.domain.criteria.PermissionSearchCriteria; -import io.github.onecx.permission.domain.models.Permission; -import io.github.onecx.permission.domain.models.Permission_; +import io.github.onecx.permission.domain.models.*; @ApplicationScoped public class PermissionDAO extends AbstractDAO { @@ -61,8 +61,31 @@ public List loadByAppId(String appId) { } } + public List findPermissionForUser(String appId, List roles) { + try { + System.out.println("# " + appId + " R " + roles); + var cb = this.getEntityManager().getCriteriaBuilder(); + var cq = cb.createQuery(Permission.class); + var root = cq.from(Permission.class); + + Subquery sq = cq.subquery(String.class); + var subRoot = sq.from(Assignment.class); + sq.select(subRoot.get(Assignment_.PERMISSION_ID)); + sq.where( + subRoot.get(Assignment_.role).get(Role_.name).in(roles), + cb.equal(subRoot.get(Assignment_.permission).get(Permission_.appId), appId)); + + cq.where(root.get(Permission_.id).in(sq)); + + return this.getEntityManager().createQuery(cq).getResultList(); + } catch (Exception ex) { + throw new DAOException(ErrorKeys.ERROR_FIND_PERMISSION_FOR_USER, ex); + } + } + public enum ErrorKeys { + ERROR_FIND_PERMISSION_FOR_USER, ERROR_LOAD_BY_APP_ID, ERROR_FIND_PERMISSION_BY_CRITERIA; } diff --git a/src/main/java/io/github/onecx/permission/domain/models/Assignment.java b/src/main/java/io/github/onecx/permission/domain/models/Assignment.java index 712e7c9..1f1dd97 100644 --- a/src/main/java/io/github/onecx/permission/domain/models/Assignment.java +++ b/src/main/java/io/github/onecx/permission/domain/models/Assignment.java @@ -13,6 +13,8 @@ @Entity @Table(name = "ASSIGNMENT", uniqueConstraints = { @UniqueConstraint(name = "ASSIGNMENT_KEY", columnNames = { "TENANT_ID", "ROLE_ID", "PERMISSION_ID" }) +}, indexes = { + @Index(name = "ASSIGNMENT_TENANT_ID", columnList = "TENANT_ID") }) public class Assignment extends TraceableEntity { diff --git a/src/main/java/io/github/onecx/permission/domain/models/Permission.java b/src/main/java/io/github/onecx/permission/domain/models/Permission.java index 2666171..bd9c60b 100644 --- a/src/main/java/io/github/onecx/permission/domain/models/Permission.java +++ b/src/main/java/io/github/onecx/permission/domain/models/Permission.java @@ -1,9 +1,6 @@ package io.github.onecx.permission.domain.models; -import jakarta.persistence.Column; -import jakarta.persistence.Entity; -import jakarta.persistence.Table; -import jakarta.persistence.UniqueConstraint; +import jakarta.persistence.*; import org.tkit.quarkus.jpa.models.TraceableEntity; @@ -14,7 +11,9 @@ @Setter @Entity @Table(name = "PERMISSION", uniqueConstraints = { - @UniqueConstraint(name = "PERMISSION_KEY", columnNames = { "APP_ID", "RESOURCE", "ACTION" }) + @UniqueConstraint(name = "PERMISSION_KEY", columnNames = { "APP_ID", "RESOURCE", "ACTION" }), +}, indexes = { + @Index(name = "PERMISSION_APP_ID", columnList = "APP_ID") }) @SuppressWarnings("squid:S2160") public class Permission extends TraceableEntity { diff --git a/src/main/java/io/github/onecx/permission/domain/models/Role.java b/src/main/java/io/github/onecx/permission/domain/models/Role.java index 53a4d62..633c706 100644 --- a/src/main/java/io/github/onecx/permission/domain/models/Role.java +++ b/src/main/java/io/github/onecx/permission/domain/models/Role.java @@ -1,9 +1,6 @@ package io.github.onecx.permission.domain.models; -import jakarta.persistence.Column; -import jakarta.persistence.Entity; -import jakarta.persistence.Table; -import jakarta.persistence.UniqueConstraint; +import jakarta.persistence.*; import org.hibernate.annotations.TenantId; import org.tkit.quarkus.jpa.models.TraceableEntity; @@ -16,6 +13,8 @@ @Entity @Table(name = "ROLE", uniqueConstraints = { @UniqueConstraint(name = "ROLE_NAME", columnNames = { "TENANT_ID", "NAME" }) +}, indexes = { + @Index(name = "ROLE_NAME", columnList = "NAME") }) @SuppressWarnings("java:S2160") public class Role extends TraceableEntity { diff --git a/src/main/java/io/github/onecx/permission/rs/external/v1/controllers/PermissionRestController.java b/src/main/java/io/github/onecx/permission/rs/external/v1/controllers/PermissionRestController.java new file mode 100644 index 0000000..fdd5abc --- /dev/null +++ b/src/main/java/io/github/onecx/permission/rs/external/v1/controllers/PermissionRestController.java @@ -0,0 +1,45 @@ +package io.github.onecx.permission.rs.external.v1.controllers; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; +import jakarta.ws.rs.core.Response; + +import org.tkit.quarkus.log.cdi.LogExclude; +import org.tkit.quarkus.log.cdi.LogService; + +import gen.io.github.onecx.permission.rs.v1.PermissionApiV1; +import io.github.onecx.permission.common.services.TokenService; +import io.github.onecx.permission.domain.daos.PermissionDAO; +import io.github.onecx.permission.rs.external.v1.mappers.PermissionMapper; + +@LogService +@ApplicationScoped +public class PermissionRestController implements PermissionApiV1 { + + @Inject + TokenService tokenService; + + @Inject + PermissionDAO permissionDAO; + + @Inject + PermissionMapper mapper; + + @Override + public Response getApplicationPermissions(String appId, @LogExclude String body) { + var roles = tokenService.getTokenRoles(body); + var permissions = permissionDAO.findPermissionForUser(appId, roles); + return Response.ok(mapper.create(appId, permissions)).build(); + } + + @Override + public Response getWorkspacePermission(String workspace, @LogExclude String body) { + return null; + } + + @Override + public Response getWorkspacePermissionApplications(String workspace, @LogExclude String body) { + return null; + } + +} diff --git a/src/main/java/io/github/onecx/permission/rs/external/v1/mappers/PermissionMapper.java b/src/main/java/io/github/onecx/permission/rs/external/v1/mappers/PermissionMapper.java new file mode 100644 index 0000000..9a6627d --- /dev/null +++ b/src/main/java/io/github/onecx/permission/rs/external/v1/mappers/PermissionMapper.java @@ -0,0 +1,30 @@ +package io.github.onecx.permission.rs.external.v1.mappers; + +import java.util.*; + +import org.mapstruct.Mapper; + +import gen.io.github.onecx.permission.rs.v1.model.ApplicationPermissionsDTOV1; +import io.github.onecx.permission.domain.models.Permission; + +@Mapper +public interface PermissionMapper { + + default Map> permissions(List permissions) { + if (permissions == null) { + return null; + } + Map> result = new HashMap<>(); + permissions.forEach(permission -> result.computeIfAbsent(permission.getResource(), k -> new HashSet<>()) + .add(permission.getAction())); + return result; + } + + default ApplicationPermissionsDTOV1 create(String appId, Map> permissions) { + return new ApplicationPermissionsDTOV1().appId(appId).permissions(permissions); + } + + default ApplicationPermissionsDTOV1 create(String appId, List permissions) { + return create(appId, permissions(permissions)); + } +} diff --git a/src/main/java/io/github/onecx/permission/rs/v1/controllers/PermissionRestController.java b/src/main/java/io/github/onecx/permission/rs/v1/controllers/PermissionRestController.java deleted file mode 100644 index 29704a3..0000000 --- a/src/main/java/io/github/onecx/permission/rs/v1/controllers/PermissionRestController.java +++ /dev/null @@ -1,29 +0,0 @@ -package io.github.onecx.permission.rs.v1.controllers; - -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.ws.rs.core.Response; - -import org.tkit.quarkus.log.cdi.LogService; - -import gen.io.github.onecx.permission.rs.v1.PermissionApiV1; - -@LogService -@ApplicationScoped -public class PermissionRestController implements PermissionApiV1 { - - @Override - public Response getApplicationPermission(String appId, String body) { - return null; - } - - @Override - public Response getWorkspacePermission(String workspace, String body) { - return null; - } - - @Override - public Response getWorkspacePermissionApplications(String workspace, String body) { - return null; - } - -} diff --git a/src/main/openapi/onecx-permission-v1.yaml b/src/main/openapi/onecx-permission-v1.yaml index 5042242..d4982c9 100644 --- a/src/main/openapi/onecx-permission-v1.yaml +++ b/src/main/openapi/onecx-permission-v1.yaml @@ -35,7 +35,7 @@ paths: schema: type: array items: - $ref: '#/components/schemas/ApplicationPermissionList' + $ref: '#/components/schemas/WorkspacePermissions' 400: description: Bad request content: @@ -69,7 +69,7 @@ paths: schema: type: array items: - $ref: '#/components/schemas/ApplicationPermissionList' + $ref: '#/components/schemas/WorkspacePermissionApplications' 400: description: Bad request content: @@ -80,8 +80,8 @@ paths: post: tags: - permission - description: Get permission of the application for the user - operationId: getApplicationPermission + description: Get permissions of the application for the user + operationId: getApplicationPermissions parameters: - name: appId in: path @@ -103,7 +103,7 @@ paths: schema: type: array items: - $ref: '#/components/schemas/ApplicationPermission' + $ref: '#/components/schemas/ApplicationPermissions' 400: description: Bad request content: @@ -112,31 +112,43 @@ paths: $ref: '#/components/schemas/ProblemDetailResponse' components: schemas: - ApplicationPermissionList: + WorkspacePermissionApplications: type: object properties: + workspace: + $ref: '#/components/schemas/WorkspacePermissions' applications: type: array items: - $ref: '#/components/schemas/ApplicationPermission' - ApplicationPermission: + $ref: '#/components/schemas/ApplicationPermissions' + WorkspacePermissions: type: object properties: - appId: + workspaceId: type: string permissions: - type: array - items: - $ref: '#/components/schemas/ResourcePermissions' - ResourcePermissions: + type: object + nullable: false + description: resources + additionalProperties: + type: array + items: + type: string + uniqueItems: true + ApplicationPermissions: type: object properties: - resource: + appId: type: string - actions: - type: array - items: - type: string + permissions: + type: object + nullable: false + description: resources + additionalProperties: + type: array + items: + type: string + uniqueItems: true ProblemDetailResponse: type: object properties: diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index dfb480f..1dc660c 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -5,12 +5,18 @@ quarkus.datasource.jdbc.min-size=10 quarkus.hibernate-orm.database.generation=validate quarkus.hibernate-orm.multitenant=DISCRIMINATOR +quarkus.hibernate-orm.log.format-sql=true +quarkus.hibernate-orm.log.sql=true quarkus.liquibase.migrate-at-start=true quarkus.liquibase.validate-on-migrate=true # enable or disable multi-tenancy support tkit.rs.context.tenant-id.enabled=true +onecx.permission.token.verified=true +onecx.permission.token.issuer.public-key-location.suffix=/protocol/openid-connect/certs +onecx.permission.token.issuer.public-key-location.enabled=false + tkit.dataimport.enabled=false tkit.dataimport.configurations.permission.file=dev-data.import.json tkit.dataimport.configurations.permission.metadata.operation=CLEAN_INSERT @@ -21,7 +27,9 @@ tkit.dataimport.configurations.permission.stop-at-error=true %prod.quarkus.datasource.jdbc.url=${DB_URL:jdbc:postgresql://postgresdb:5432/onecx-permission?sslmode=disable} %prod.quarkus.datasource.username=${DB_USER:onecx-permission} %prod.quarkus.datasource.password=${DB_PWD:onecx-permission} + # DEV +%dev.onecx.permission.token.verified=false %dev.tkit.rs.context.tenant-id.enabled=true %dev.tkit.rs.context.tenant-id.mock.enabled=true %dev.tkit.rs.context.tenant-id.mock.default-tenant=test @@ -29,6 +37,7 @@ tkit.dataimport.configurations.permission.stop-at-error=true # TEST quarkus.test.integration-test-profile=test +%test.onecx.permission.token.verified=false %test.tkit.rs.context.tenant-id.enabled=true %test.tkit.rs.context.tenant-id.mock.enabled=true %test.tkit.rs.context.tenant-id.mock.default-tenant=default diff --git a/src/main/resources/db/v1/2024-01-04-create-tables.xml b/src/main/resources/db/v1/2024-01-04-create-tables.xml index e264b04..88c912e 100644 --- a/src/main/resources/db/v1/2024-01-04-create-tables.xml +++ b/src/main/resources/db/v1/2024-01-04-create-tables.xml @@ -115,5 +115,14 @@ + + + + + + + + + diff --git a/src/test/java/io/github/onecx/permission/domain/daos/PermissionDAOTest.java b/src/test/java/io/github/onecx/permission/domain/daos/PermissionDAOTest.java index 869aceb..a83494f 100644 --- a/src/test/java/io/github/onecx/permission/domain/daos/PermissionDAOTest.java +++ b/src/test/java/io/github/onecx/permission/domain/daos/PermissionDAOTest.java @@ -14,6 +14,8 @@ class PermissionDAOTest extends AbstractDAOTest { @Test void methodExceptionTests() { + methodExceptionTests(() -> dao.findPermissionForUser(null, null), + PermissionDAO.ErrorKeys.ERROR_FIND_PERMISSION_FOR_USER); methodExceptionTests(() -> dao.loadByAppId(null), PermissionDAO.ErrorKeys.ERROR_LOAD_BY_APP_ID); methodExceptionTests(() -> dao.findByCriteria(null), diff --git a/src/test/java/io/github/onecx/permission/rs/external/v1/PermissionRestControllerTest.java b/src/test/java/io/github/onecx/permission/rs/external/v1/PermissionRestControllerTest.java new file mode 100644 index 0000000..8e5461b --- /dev/null +++ b/src/test/java/io/github/onecx/permission/rs/external/v1/PermissionRestControllerTest.java @@ -0,0 +1,38 @@ +package io.github.onecx.permission.rs.external.v1; + +import static io.restassured.RestAssured.given; +import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON; +import static org.jboss.resteasy.reactive.RestResponse.Status.OK; + +import java.util.List; + +import org.junit.jupiter.api.Test; +import org.tkit.quarkus.test.WithDBData; + +import gen.io.github.onecx.permission.rs.v1.model.ApplicationPermissionsDTOV1; +import io.github.onecx.permission.rs.external.v1.controllers.PermissionRestController; +import io.github.onecx.permission.test.AbstractTest; +import io.quarkus.test.common.http.TestHTTPEndpoint; +import io.quarkus.test.junit.QuarkusTest; + +@QuarkusTest +@TestHTTPEndpoint(PermissionRestController.class) +@WithDBData(value = "data/test-v1.xml", deleteBeforeInsert = true, deleteAfterTest = true, rinseAndRepeat = true) +public class PermissionRestControllerTest extends AbstractTest { + + @Test + void getApplicationPermissionsTest() { + + var accessToken = createToken(List.of("n3")); + + var dto = given() + .contentType(APPLICATION_JSON) + .body(accessToken) + .post("/application/app1") + .then().log().all() + .statusCode(OK.getStatusCode()) + .extract() + .body().as(ApplicationPermissionsDTOV1.class); + + } +} diff --git a/src/test/java/io/github/onecx/permission/rs/external/v1/PermissionRestControllerTestIT.java b/src/test/java/io/github/onecx/permission/rs/external/v1/PermissionRestControllerTestIT.java new file mode 100644 index 0000000..0ba63fd --- /dev/null +++ b/src/test/java/io/github/onecx/permission/rs/external/v1/PermissionRestControllerTestIT.java @@ -0,0 +1,8 @@ +package io.github.onecx.permission.rs.external.v1; + +import io.quarkus.test.junit.QuarkusIntegrationTest; + +@QuarkusIntegrationTest +class PermissionRestControllerTestIT extends PermissionRestControllerTest { + +} diff --git a/src/test/java/io/github/onecx/permission/test/AbstractTest.java b/src/test/java/io/github/onecx/permission/test/AbstractTest.java index d110fe8..7430dc6 100644 --- a/src/test/java/io/github/onecx/permission/test/AbstractTest.java +++ b/src/test/java/io/github/onecx/permission/test/AbstractTest.java @@ -5,6 +5,7 @@ import static io.restassured.config.ObjectMapperConfig.objectMapperConfig; import java.security.PrivateKey; +import java.util.List; import jakarta.json.Json; import jakarta.json.JsonObjectBuilder; @@ -37,12 +38,28 @@ public class AbstractTest { } protected static String createToken(String organizationId) { + return createToken(organizationId, null); + } + + protected static String createToken(List roles) { + return createToken(null, roles); + } + + protected static String createToken(String organizationId, List roles) { try { + String userName = "test-user"; JsonObjectBuilder claims = Json.createObjectBuilder(); claims.add(Claims.preferred_username.name(), userName); claims.add(Claims.sub.name(), userName); - claims.add(CLAIMS_ORG_ID, organizationId); + if (organizationId != null) { + claims.add(CLAIMS_ORG_ID, organizationId); + } + if (roles != null && !roles.isEmpty()) { + JsonObjectBuilder r = Json.createObjectBuilder(); + r.add("roles", Json.createArrayBuilder(roles)); + claims.add("realm_access", r); + } PrivateKey privateKey = KeyUtils.generateKeyPair(2048).getPrivate(); return Jwt.claims(claims.build()).sign(privateKey); } catch (Exception ex) { diff --git a/src/test/resources/data/test-v1.xml b/src/test/resources/data/test-v1.xml index 64f4e9b..92cd883 100644 --- a/src/test/resources/data/test-v1.xml +++ b/src/test/resources/data/test-v1.xml @@ -24,4 +24,17 @@ + + + + + + + + + + + + + \ No newline at end of file