Skip to content

Commit

Permalink
#145 view User Attributes in account console
Browse files Browse the repository at this point in the history
  • Loading branch information
cgeorgilakis committed Dec 7, 2021
1 parent 12fe5e0 commit c48ed19
Show file tree
Hide file tree
Showing 19 changed files with 223 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import org.keycloak.common.Version;
import org.keycloak.migration.migrators.MigrateTo12_0_0;
import org.keycloak.migration.migrators.MigrateTo14_0_0;
import org.keycloak.migration.migrators.MigrateTo16_0_0;
import org.keycloak.migration.migrators.MigrateTo1_2_0;
import org.keycloak.migration.migrators.MigrateTo1_3_0;
import org.keycloak.migration.migrators.MigrateTo1_4_0;
Expand Down Expand Up @@ -96,7 +97,8 @@ public class MigrationModelManager {
new MigrateTo9_0_0(),
new MigrateTo9_0_4(),
new MigrateTo12_0_0(),
new MigrateTo14_0_0()
new MigrateTo14_0_0(),
new MigrateTo16_0_0()
};

public static void migrate(KeycloakSession session) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package org.keycloak.migration.migrators;

import org.keycloak.migration.ModelVersion;
import org.keycloak.models.AccountRoles;
import org.keycloak.models.ClientModel;
import org.keycloak.models.Constants;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleModel;
import org.keycloak.representations.idm.RealmRepresentation;

public class MigrateTo16_0_0 implements Migration {

public static final ModelVersion VERSION = new ModelVersion("16.0.0");

@Override
public void migrate(KeycloakSession session) {

session.realms().getRealmsStream().forEach(this::changeManageAccount);
}

@Override
public void migrateImport(KeycloakSession session, RealmModel realm, RealmRepresentation rep, boolean skipUserDependent) {
changeManageAccount(realm);
}

private void changeManageAccount(RealmModel realm) {
ClientModel accountClient = realm.getClientByClientId(Constants.ACCOUNT_MANAGEMENT_CLIENT_ID);
if (accountClient != null && accountClient.getRole(AccountRoles.VIEW_ATTRIBUTES) == null) {
RoleModel manageEmail = accountClient.addRole(AccountRoles.VIEW_ATTRIBUTES);
manageEmail.setDescription("${role_" + AccountRoles.VIEW_ATTRIBUTES + "}");
}
}

@Override
public ModelVersion getVersion() {
return VERSION;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
public interface AccountRoles {

String VIEW_PROFILE = "view-profile";
String VIEW_ATTRIBUTES = "view-attributes";
String MANAGE_ACCOUNT = "manage-account";
String MANAGE_ACCOUNT_LINKS = "manage-account-links";
String VIEW_APPLICATIONS = "view-applications";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -438,6 +438,8 @@ private void setupAccountManagement(RealmModel realm) {
RoleModel manageConsentRole = accountClient.addRole(AccountRoles.MANAGE_CONSENT);
manageConsentRole.setDescription("${role_" + AccountRoles.MANAGE_CONSENT + "}");
manageConsentRole.addCompositeRole(viewConsentRole);
RoleModel viewAttributes = accountClient.addRole(AccountRoles.VIEW_ATTRIBUTES);
viewAttributes.setDescription("${role_" + AccountRoles.VIEW_ATTRIBUTES + "}");

KeycloakModelUtils.setupDeleteAccount(accountClient);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,16 +134,21 @@ public Response getMainPage() throws IOException, FreeMarkerException {

boolean isTotpConfigured = false;
boolean deleteAccountAllowed = false;
boolean viewAttributes = false;
if (user != null) {
isTotpConfigured = session.userCredentialManager().isConfiguredFor(realm, user, realm.getOTPPolicy().getType());
RoleModel deleteAccountRole = realm.getClientByClientId(Constants.ACCOUNT_MANAGEMENT_CLIENT_ID).getRole(AccountRoles.DELETE_ACCOUNT);
deleteAccountAllowed = deleteAccountRole != null && user.hasRole(deleteAccountRole) && realm.getRequiredActionProviderByAlias(DeleteAccount.PROVIDER_ID).isEnabled();
RoleModel viewAttributesRole = realm.getClientByClientId(Constants.ACCOUNT_MANAGEMENT_CLIENT_ID).getRole(AccountRoles.VIEW_ATTRIBUTES);
viewAttributes = viewAttributesRole != null && user.hasRole(viewAttributesRole);
}

map.put("isTotpConfigured", isTotpConfigured);

map.put("deleteAccountAllowed", deleteAccountAllowed);

map.put("viewAttributes", viewAttributes);

FreeMarkerUtil freeMarkerUtil = new FreeMarkerUtil();
String result = freeMarkerUtil.processTemplate(map, "index.ftl", theme);
Response.ResponseBuilder builder = Response.status(Response.Status.OK).type(MediaType.TEXT_HTML_UTF_8).language(Locale.ENGLISH).entity(result);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -502,6 +502,21 @@ public Stream<ClientRepresentation> applications(@QueryParam("name") String name
.map(client -> modelToRepresentation(client, inUseClients, offlineClients, consentModels));
}

@Path("/attributes")
@GET
@NoCache
@Produces(MediaType.APPLICATION_JSON)
public Map<String,List<String>> getAttributes() {
auth.requireOneOf(AccountRoles.MANAGE_ACCOUNT, AccountRoles.VIEW_ATTRIBUTES);
Map<String,List<String>> attributes = user.getAttributes();
attributes.remove(UserModel.LAST_NAME);
attributes.remove(UserModel.FIRST_NAME);
attributes.remove(UserModel.EMAIL);
attributes.remove(UserModel.USERNAME);
return attributes;
}


private boolean matches(ClientModel client, String name) {
if(name == null)
return true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -595,7 +595,7 @@ public void scopes() {
Assert.assertNames(scopesResource.clientLevel(accountMgmtId).listAll(), AccountRoles.VIEW_PROFILE);
Assert.assertNames(scopesResource.clientLevel(accountMgmtId).listEffective(), AccountRoles.VIEW_PROFILE);

Assert.assertNames(scopesResource.clientLevel(accountMgmtId).listAvailable(), AccountRoles.MANAGE_ACCOUNT, AccountRoles.MANAGE_ACCOUNT_LINKS, AccountRoles.VIEW_APPLICATIONS, AccountRoles.VIEW_CONSENT, AccountRoles.MANAGE_CONSENT, AccountRoles.DELETE_ACCOUNT);
Assert.assertNames(scopesResource.clientLevel(accountMgmtId).listAvailable(), AccountRoles.MANAGE_ACCOUNT, AccountRoles.MANAGE_ACCOUNT_LINKS, AccountRoles.VIEW_APPLICATIONS, AccountRoles.VIEW_CONSENT, AccountRoles.MANAGE_CONSENT, AccountRoles.DELETE_ACCOUNT, AccountRoles.VIEW_ATTRIBUTES);

Assert.assertNames(scopesResource.getAll().getRealmMappings(), "realm-composite");
Assert.assertNames(scopesResource.getAll().getClientMappings().get(Constants.ACCOUNT_MANAGEMENT_CLIENT_ID).getMappings(), AccountRoles.VIEW_PROFILE);
Expand All @@ -611,7 +611,7 @@ public void scopes() {
Assert.assertNames(scopesResource.realmLevel().listAvailable(), "offline_access", Constants.AUTHZ_UMA_AUTHORIZATION, "realm-composite", "realm-child", Constants.DEFAULT_ROLES_ROLE_PREFIX + "-" + REALM_NAME);
Assert.assertNames(scopesResource.clientLevel(accountMgmtId).listAll());

Assert.assertNames(scopesResource.clientLevel(accountMgmtId).listAvailable(), AccountRoles.VIEW_PROFILE, AccountRoles.MANAGE_ACCOUNT, AccountRoles.MANAGE_ACCOUNT_LINKS, AccountRoles.VIEW_APPLICATIONS, AccountRoles.VIEW_CONSENT, AccountRoles.MANAGE_CONSENT, AccountRoles.DELETE_ACCOUNT);
Assert.assertNames(scopesResource.clientLevel(accountMgmtId).listAvailable(), AccountRoles.VIEW_PROFILE, AccountRoles.MANAGE_ACCOUNT, AccountRoles.MANAGE_ACCOUNT_LINKS, AccountRoles.VIEW_APPLICATIONS, AccountRoles.VIEW_CONSENT, AccountRoles.MANAGE_CONSENT, AccountRoles.DELETE_ACCOUNT,AccountRoles.VIEW_ATTRIBUTES);

Assert.assertNames(scopesResource.clientLevel(accountMgmtId).listEffective());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,11 @@ protected void testMigrationTo14_0_0() {
testSamlAttributes(migrationRealm);
}

protected void testMigrationTo16_0_0() {
testViewAttributes(masterRealm);
testViewAttributes(migrationRealm);
}

protected void testDeleteAccount(RealmResource realm) {
ClientRepresentation accountClient = realm.clients().findByClientId(ACCOUNT_MANAGEMENT_CLIENT_ID).get(0);
ClientResource accountResource = realm.clients().get(accountClient.getId());
Expand Down Expand Up @@ -882,6 +887,15 @@ protected void testUserLocaleActionAdded(RealmResource realm) {
assertFalse(rep.isDefaultAction());
}

protected void testViewAttributes(RealmResource realm) {
ClientRepresentation accountClient = realm.clients().findByClientId(ACCOUNT_MANAGEMENT_CLIENT_ID).get(0);

ClientResource accountResource = realm.clients().get(accountClient.getId());
RoleRepresentation viewAppRole = accountResource.roles().get(AccountRoles.VIEW_ATTRIBUTES).toRepresentation();
assertNotNull(viewAppRole);
}


protected void testMigrationTo2_x() throws Exception {
testMigrationTo2_0_0();
testMigrationTo2_1_0();
Expand Down Expand Up @@ -937,6 +951,11 @@ protected void testMigrationTo7_x(boolean supportedAuthzServices) {
}
}

protected void testMigrationTo16_x() {
testMigrationTo16_0_0();
}


protected void testResourceTag() {
try (CloseableHttpClient client = HttpClientBuilder.create().build()) {
URI url = suiteContext.getAuthServerInfo().getUriBuilder().path("/auth").build();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ public void migration1_9_8Test() {
testMigrationTo8_x();
testMigrationTo9_x();
testMigrationTo12_x(false);
testMigrationTo16_x();
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ public void migration2_5_5Test() throws Exception {
testMigrationTo8_x();
testMigrationTo9_x();
testMigrationTo12_x(false);
testMigrationTo16_x();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ public void migration3_4_3Test() throws Exception {
testMigrationTo8_x();
testMigrationTo9_x();
testMigrationTo12_x(true);
testMigrationTo16_x();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ public void migration4_8_3Test() throws Exception {
testMigrationTo8_x();
testMigrationTo9_x();
testMigrationTo12_x(true);
testMigrationTo16_x();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ public void addTestRealms(List<RealmRepresentation> testRealms) {
public void migration9_0_3Test() throws Exception {
checkRealmsImported();
testMigrationTo12_x(true);
testMigrationTo16_x();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ public void migration4_xTest() throws Exception {
testMigrationTo8_x();
testMigrationTo9_x();
testMigrationTo12_x(true);
testMigrationTo16_x();

// Always test offline-token login during migration test
testOfflineTokenLogin();
Expand All @@ -97,6 +98,7 @@ public void migration3_xTest() throws Exception {
testMigrationTo8_x();
testMigrationTo9_x();
testMigrationTo12_x(true);
testMigrationTo16_x();

// Always test offline-token login during migration test
testOfflineTokenLogin();
Expand All @@ -122,6 +124,7 @@ public void migration2_xTest() throws Exception {
testMigrationTo8_x();
testMigrationTo9_x();
testMigrationTo12_x(false);
testMigrationTo16_x();

// Always test offline-token login during migration test
testOfflineTokenLogin();
Expand All @@ -140,6 +143,7 @@ public void migration1_xTest() throws Exception {
testMigrationTo8_x();
testMigrationTo9_x();
testMigrationTo12_x(false);
testMigrationTo16_x();

// Always test offline-token login during migration test
testOfflineTokenLogin();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ role_manage-identity-providers=Manage identity providers
role_manage-clients=Manage clients
role_manage-events=Manage events
role_view-profile=View profile
role_view-attributes=View user attributes
role_manage-account=Manage account
role_manage-account-links=Manage account links
role_manage-consent=Manage consents
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@
isEventsEnabled : ${isEventsEnabled?c},
isMyResourcesEnabled : ${(realm.userManagedAccessAllowed && isAuthorizationEnabled)?c},
isTotpConfigured : ${isTotpConfigured?c},
deleteAccountAllowed : ${deleteAccountAllowed?c}
deleteAccountAllowed : ${deleteAccountAllowed?c},
viewAttributes : ${viewAttributes?c}
}
var availableLocales = [];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,13 @@ deleteAccountSummary=Deleting your account will erase all your data and log you
deleteAccount=Delete Account
deleteAccountWarning=This is irreversible. All your data will be permanently destroyed, and irretrievable.

#View user attributes
personalInfoGeneralMessage=Manage your basic information and view your attributes
viewAttributes=View your attributes
attributes=Attributes
key=Key
value=Value

error-invalid-value=''{0}'' has invalid value.
error-invalid-blank=Please specify value of ''{0}''.
error-empty=Please specify value of ''{0}''.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,24 @@
"path": "personal-info",
"icon": "pf-icon-user",
"label": "personalInfoHtmlTitle",
"descriptionLabel": "personalInfoIntroMessage",
"modulePath": "/content/account-page/AccountPage.js",
"componentName": "AccountPage"
"descriptionLabel": "personalInfoGeneralMessage",
"content": [
{
"id": "manage",
"path": "personal-info/manage",
"label": "personalInfoIntroMessage",
"modulePath": "/content/account-page/AccountPage.js",
"componentName": "AccountPage"
},
{
"id": "view-attributes",
"path": "personal-info/view-attributes",
"label": "viewAttributes",
"modulePath": "/content/account-page/ViewAttributesPage.js",
"componentName": "ViewAttributes",
"hidden": "!features.viewAttributes"
}
]
},
{
"id": "security",
Expand Down
Loading

0 comments on commit c48ed19

Please sign in to comment.