Skip to content

Commit

Permalink
feat: get specific user-menu by key (#46)
Browse files Browse the repository at this point in the history
  • Loading branch information
JordenReuter authored Mar 26, 2024
1 parent ae26fa9 commit 8c206b3
Show file tree
Hide file tree
Showing 9 changed files with 172 additions and 29 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import org.tkit.onecx.workspace.domain.models.AssignmentMenu;
import org.tkit.onecx.workspace.rs.user.mappers.ExceptionMapper;
import org.tkit.onecx.workspace.rs.user.mappers.UserMenuMapper;
import org.tkit.onecx.workspace.rs.user.services.MenuMappingConfig;
import org.tkit.onecx.workspace.rs.user.services.TokenService;
import org.tkit.quarkus.log.cdi.LogExclude;
import org.tkit.quarkus.log.cdi.LogService;
Expand Down Expand Up @@ -53,9 +54,20 @@ public class UserMenuInternalController implements UserMenuInternalApi {
@Inject
UserMenuMapper mapper;

@Inject
MenuMappingConfig mappingConfig;

@Override
public Response getUserMenu(String workspaceName, @LogExclude UserWorkspaceMenuRequestDTO userWorkspaceMenuRequestDTO) {
var roles = tokenService.getTokenRoles(userWorkspaceMenuRequestDTO.getToken());
HashSet<String> menuKeys = new HashSet<>();
if (userWorkspaceMenuRequestDTO.getMenuKeys() != null) {
userWorkspaceMenuRequestDTO.getMenuKeys().forEach(s -> {
if (mappingConfig.userConfig().mapping().containsKey(s)) {
menuKeys.add(mappingConfig.userConfig().mapping().get(s));
}
});
}

var workspace = workspaceDAO.findByName(workspaceName);
if (workspace == null) {
Expand All @@ -75,7 +87,8 @@ public Response getUserMenu(String workspaceName, @LogExclude UserWorkspaceMenuR
criteria.setWorkspaceId(workspace.getId());
var items = menuItemDAO.loadAllMenuItemsByCriteria(criteria);

return Response.ok(mapper.mapTree(workspaceName, items, mapping, new HashSet<>(roles))).build();
return Response.ok(mapper.mapTree(workspaceName, items, mapping, new HashSet<>(roles), menuKeys))
.build();
}

@ServerExceptionMapper
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,20 @@ default UserWorkspaceMenuStructureDTO empty(String workspaceName) {
}

default UserWorkspaceMenuStructureDTO mapTree(String workspaceName, Collection<MenuItem> entities,
Map<String, Set<String>> mapping, Set<String> roles) {
Map<String, Set<String>> mapping, Set<String> roles, Set<String> mappingKeys) {
UserWorkspaceMenuStructureDTO dto = empty(workspaceName);
if (entities.isEmpty()) {
return dto;
}

var items = entities.stream().filter(m -> m.getParentId() == null).collect(Collectors.toSet());
Set<MenuItem> items;
if (!mappingKeys.isEmpty()) {
items = entities.stream().filter(m -> m.getParentId() == null)
.filter(m -> mappingKeys.contains(m.getKey()))
.collect(Collectors.toSet());
} else {
items = entities.stream().filter(m -> m.getParentId() == null)
.collect(Collectors.toSet());
}
items = filterMenu(items, mapping, roles);
if (items.isEmpty()) {
return dto;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public class ClaimService {
@PostConstruct
@SuppressWarnings("java:S2696")
public void init() {
claimPath = splitClaimPath(config.claimPath());
claimPath = splitClaimPath(config.token().claimPath());
}

public String[] getClaimPath() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package org.tkit.onecx.workspace.rs.user.services;

import java.util.Map;

import io.quarkus.runtime.annotations.StaticInitSafe;
import io.smallrye.config.ConfigMapping;
import io.smallrye.config.WithName;

@StaticInitSafe
@ConfigMapping(prefix = "onecx.workspace")
public interface MenuMappingConfig {
/**
*
* @return user configs
*/
@WithName("user.menu")
UserConfig userConfig();

interface UserConfig {
/**
*
* @return menu mapping keys
*/
@WithName("mapping")
Map<String, String> mapping();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,25 +8,53 @@
import io.smallrye.config.WithName;

@StaticInitSafe
@ConfigMapping(prefix = "onecx.workspace.token")
@ConfigMapping(prefix = "onecx.workspace")
public interface TokenConfig {

@WithName("verified")
@WithDefault("false")
boolean verified();

@WithName("issuer.public-key-location.suffix")
@WithDefault("/protocol/openid-connect/certs")
String publicKeyLocationSuffix();

@WithName("issuer.public-key-location.enabled")
@WithDefault("false")
boolean publicKeyEnabled();

@WithName("claim.separator")
Optional<String> claimSeparator();

@WithName("claim.path")
@WithDefault("realm_access/roles")
String claimPath();
/**
*
* @return token configs
*/
@WithName("token")
Token token();

interface Token {
/**
*
* @return verification status
*/
@WithName("verified")
@WithDefault("false")
boolean verified();

/**
*
* @return suffix of public key
*/
@WithName("issuer.public-key-location.suffix")
@WithDefault("/protocol/openid-connect/certs")
String publicKeyLocationSuffix();

/**
*
* @return status if public key is enabled
*/
@WithName("issuer.public-key-location.enabled")
@WithDefault("false")
boolean publicKeyEnabled();

/**
*
* @return separator
*/
@WithName("claim.separator")
Optional<String> claimSeparator();

/**
*
* @return claim path
*/
@WithName("claim.path")
@WithDefault("realm_access/roles")
String claimPath();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,13 @@ public List<String> getTokenRoles(String tokenData) {
}

var request = new TokenParserRequest(token)
.verify(config.verified())
.issuerEnabled(config.publicKeyEnabled())
.issuerSuffix(config.publicKeyLocationSuffix());
.verify(config.token().verified())
.issuerEnabled(config.token().publicKeyEnabled())
.issuerSuffix(config.token().publicKeyLocationSuffix());

var permissionToken = tokenParserService.parseToken(request);
var path = claimService.getClaimPath();
return TokenClaimUtility.findClaimStringList(permissionToken, path, config.claimSeparator().orElse(" "));
return TokenClaimUtility.findClaimStringList(permissionToken, path, config.token().claimSeparator().orElse(" "));

} catch (Exception ex) {
throw new TokenException("Error parsing permission token", ex);
Expand Down
4 changes: 4 additions & 0 deletions src/main/openapi/onecx-user-internal-openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@ components:
properties:
token:
type: string
menuKeys:
type: array
items:
type: string
UserWorkspaceMenuStructure:
type: object
properties:
Expand Down
6 changes: 6 additions & 0 deletions src/main/resources/application.properties
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ onecx.workspace.token.claim.path=realm_access/roles
onecx.workspace.token.issuer.public-key-location.enabled=false
onecx.workspace.token.issuer.public-key-location.suffix=/protocol/openid-connect/certs

onecx.workspace.user.menu.mapping.main-menu=PORTAL_MAIN_MENU
onecx.workspace.user.menu.mapping.user-profile-menu=USER_PROFILE_MENU
onecx.workspace.user.menu.mapping.footer-menu=PORTAL_FOOTER_MENU

tkit.dataimport.enabled=false
tkit.dataimport.configurations.workspace.file=dev-data.import.json
tkit.dataimport.configurations.workspace.metadata.operation=CLEAN_INSERT
Expand Down Expand Up @@ -55,6 +59,8 @@ tkit.rs.context.tenant-id.enabled=true
%test.tkit.rs.context.tenant-id.mock.data.org2=tenant-200
%test.tkit.rs.context.tenant-id.mock.data.org3=tenant-300

%test.onecx.workspace.user.menu.mapping.main-menu=key42

# TEST-IT (integration tests)
quarkus.test.integration-test-profile=test

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,64 @@ void getMenuStructureForUserIdTest() {
assertThat(countMenuItems(data.getMenu())).isEqualTo(9);
}

@Test
void getMenuStructureForUserIdByMenuKeyTest() {

var workspaceName = "test03";
var accessToken = createAccessTokenBearer(USER_BOB);
var idToken = createToken("org1");

var data = given()
.when()
.contentType(APPLICATION_JSON)
.header(APM_HEADER_PARAM, idToken)
.body(new UserWorkspaceMenuRequestDTO().token(accessToken).menuKeys(List.of("main-menu", "not-existing")))
.pathParam("workspaceName", workspaceName)
.post()
.then()
.statusCode(OK.getStatusCode())
.extract().body().as(UserWorkspaceMenuStructureDTO.class);

assertThat(data).isNotNull();
assertThat(data.getWorkspaceName()).isNotNull().isEqualTo(workspaceName);
assertThat(data.getMenu()).isNotNull().isNotEmpty();

var output = print(data.getMenu(), "");
System.out.println(output);

String tmp = """
+ [1] 4-2
+ [0] 4-2-1
+ [1] 4-2-2
+ [2] 4-2-3
+ [0] 4-2-3-1
""";
assertThat(output).isEqualTo(tmp);
assertThat(countMenuItems(data.getMenu())).isEqualTo(5);

// without bearer prefix
accessToken = createAccessToken(USER_BOB);
data = given()
.when()
.contentType(APPLICATION_JSON)
.header(APM_HEADER_PARAM, idToken)
.body(new UserWorkspaceMenuRequestDTO().token(accessToken).menuKeys(List.of("main-menu", "not-existing")))
.pathParam("workspaceName", workspaceName)
.post()
.then()
.statusCode(OK.getStatusCode())
.extract().body().as(UserWorkspaceMenuStructureDTO.class);

assertThat(data).isNotNull();
assertThat(data.getWorkspaceName()).isNotNull().isEqualTo(workspaceName);
assertThat(data.getMenu()).isNotNull().isNotEmpty();

output = print(data.getMenu(), "");
System.out.println(output);
assertThat(output).isEqualTo(tmp);
assertThat(countMenuItems(data.getMenu())).isEqualTo(5);
}

@Test
void getMenuStructureForUserIdOrg2Test() {

Expand Down

0 comments on commit 8c206b3

Please sign in to comment.