Skip to content

Commit

Permalink
feat: handle event listener from keycloak when edit role
Browse files Browse the repository at this point in the history
  • Loading branch information
Sotatek-PhucNguyen5 committed Oct 4, 2023
1 parent b6b1f3e commit 83e93e1
Show file tree
Hide file tree
Showing 9 changed files with 70 additions and 13 deletions.
Expand Up @@ -10,6 +10,7 @@
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.constraints.Email;
import lombok.RequiredArgsConstructor;
import org.cardanofoundation.authentication.model.request.event.EventModel;
import org.cardanofoundation.authentication.model.response.UserInfoResponse;
import org.cardanofoundation.authentication.service.KeycloakService;
import org.cardanofoundation.explorer.common.exceptions.ErrorResponse;
Expand Down Expand Up @@ -62,7 +63,7 @@ public ResponseEntity<Boolean> checkExistEmail(
}

@PostMapping("/role-mapping")
public ResponseEntity<Boolean> roleMapping(@RequestBody String resourcePath) {
return ResponseEntity.ok(keycloakService.roleMapping(resourcePath));
public ResponseEntity<Boolean> roleMapping(@RequestBody EventModel model) {
return ResponseEntity.ok(keycloakService.roleMapping(model));
}
}
@@ -0,0 +1,5 @@
package org.cardanofoundation.authentication.model.enums;

public enum EResourceType {
REALM_ROLE_MAPPING, REALM_ROLE
}
@@ -0,0 +1,13 @@
package org.cardanofoundation.authentication.model.request.event;

import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
public class EventModel {

private String resourceType;

private String resourcePath;
}
Expand Up @@ -49,7 +49,8 @@ public List<String> getRolesFromJwtToken(String token) {
Map<String, List<String>> realmAccessMap = (Map<String, List<String>>) claims.get(
"realm_access");
if (Objects.nonNull(realmAccessMap)) {
return realmAccessMap.get("roles");
List<String> allRoles = realmAccessMap.get("roles");
return allRoles.stream().filter(role -> role.startsWith("ROLE_")).toList();
}
return Collections.emptyList();
}
Expand Down
Expand Up @@ -12,8 +12,11 @@
import org.keycloak.OAuth2Constants;
import org.keycloak.admin.client.Keycloak;
import org.keycloak.admin.client.KeycloakBuilder;
import org.keycloak.admin.client.resource.RealmResource;
import org.keycloak.admin.client.resource.RolesResource;
import org.keycloak.admin.client.resource.UsersResource;
import org.keycloak.representations.idm.CredentialRepresentation;
import org.keycloak.representations.idm.RoleRepresentation;
import org.keycloak.representations.idm.UserRepresentation;
import org.springframework.stereotype.Component;

Expand Down Expand Up @@ -82,4 +85,11 @@ public CredentialRepresentation createPasswordCredentials(String password) {
passwordCredentials.setValue(password);
return passwordCredentials;
}

public String getRoleIdByRoleName(String roleName) {
RealmResource realmResource = getInstance().realm(keycloakProperties.getRealm());
RolesResource rolesResource = realmResource.roles();
RoleRepresentation roleRepresentation = rolesResource.get(roleName).toRepresentation();
return roleRepresentation.getId();
}
}
@@ -1,6 +1,7 @@
package org.cardanofoundation.authentication.service;

import jakarta.servlet.http.HttpServletRequest;
import org.cardanofoundation.authentication.model.request.event.EventModel;
import org.cardanofoundation.authentication.model.response.UserInfoResponse;

public interface KeycloakService {
Expand All @@ -24,5 +25,5 @@ public interface KeycloakService {
* description: log out when assign, un assign role for user
* @update:
*/
Boolean roleMapping(String resourcePath);
Boolean roleMapping(EventModel model);
}
Expand Up @@ -102,6 +102,11 @@ public SignInResponse signIn(SignInRequest signInRequest) {
usersResource.get(user.getId()).update(user);
redisProvider.setValue(user.getId() + "_" + Instant.now(), response.getToken());
redisProvider.setValue(user.getId() + "_" + Instant.now(), response.getRefreshToken());
List<String> roles = jwtProvider.getRolesFromJwtToken(response.getToken());
roles.forEach(role -> {
String roleId = keycloakProvider.getRoleIdByRoleName(role);
redisProvider.setValue(roleId + "_" + Instant.now(), user.getId());
});
return SignInResponse.builder().token(response.getToken()).address(signInRequest.getAddress())
.email(signInRequest.getEmail()).tokenType(CommonConstant.TOKEN_TYPE)
.refreshToken(response.getRefreshToken()).build();
Expand Down
Expand Up @@ -2,11 +2,14 @@

import jakarta.servlet.http.HttpServletRequest;
import java.time.Instant;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.cardanofoundation.authentication.constant.CommonConstant;
import org.cardanofoundation.authentication.model.enums.EResourceType;
import org.cardanofoundation.authentication.model.request.event.EventModel;
import org.cardanofoundation.authentication.model.response.UserInfoResponse;
import org.cardanofoundation.authentication.provider.JwtProvider;
import org.cardanofoundation.authentication.provider.KeycloakProvider;
Expand Down Expand Up @@ -41,16 +44,30 @@ public UserInfoResponse infoUser(HttpServletRequest httpServletRequest) {
}

@Override
public Boolean roleMapping(String resourcePath) {
String[] resourceArr = resourcePath.split("/");
public Boolean roleMapping(EventModel model) {
String resourceType = model.getResourceType();
String[] resourceArr = model.getResourcePath().split("/");
Set<String> keys = redisProvider.getKeys(resourceArr[1] + "*");
if (Objects.nonNull(keys) && !keys.isEmpty()) {
keys.forEach(key -> {
String val = redisProvider.getValue(key);
redisProvider.blacklistJwt(val, resourceArr[1]);
redisProvider.remove(key);
});
if (resourceType.equals(EResourceType.REALM_ROLE.name())) {
Set<String> userPrefixKeys = new HashSet<>();
keys.forEach(key -> userPrefixKeys.add(redisProvider.getValue(key)));
Set<String> userKeys = new HashSet<>();
userPrefixKeys.forEach(
userPrefixKey -> userKeys.addAll(redisProvider.getKeys(userPrefixKey + "*")));
setInValidToken(userKeys);
} else {
setInValidToken(keys);
}
}
return true;
}

private void setInValidToken(Set<String> keys) {
keys.forEach(key -> {
String val = redisProvider.getValue(key);
redisProvider.blacklistJwt(val, key);
redisProvider.remove(key);
});
}
}
Expand Up @@ -10,6 +10,7 @@
import com.google.gson.Gson;
import jakarta.servlet.http.HttpServletRequest;
import java.time.Instant;
import org.cardanofoundation.authentication.model.request.event.EventModel;
import org.cardanofoundation.authentication.model.response.UserInfoResponse;
import org.cardanofoundation.authentication.provider.JwtProvider;
import org.cardanofoundation.authentication.provider.KeycloakProvider;
Expand Down Expand Up @@ -68,9 +69,12 @@ void whenCallExistEmail() throws Exception {

@Test
void whenCallRoleMapping() throws Exception {
given(keycloakService.roleMapping("resourcePathTest")).willReturn(true);
EventModel model = new EventModel();
model.setResourcePath("test");
model.setResourceType("test");
given(keycloakService.roleMapping(model)).willReturn(true);
mockMvc.perform(post("/api/v1/user/role-mapping")
.content("resourcePathTest")
.content(asJsonString(model))
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andDo(print());
Expand Down

0 comments on commit 83e93e1

Please sign in to comment.