diff --git a/core/src/main/java/org/keycloak/representations/idm/ApplicationRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/ApplicationRepresentation.java index 878092e886..59347ca49c 100755 --- a/core/src/main/java/org/keycloak/representations/idm/ApplicationRepresentation.java +++ b/core/src/main/java/org/keycloak/representations/idm/ApplicationRepresentation.java @@ -18,6 +18,7 @@ public class ApplicationRepresentation { protected boolean enabled; protected List credentials; protected List roles; + protected String[] defaultRoles; protected List roleMappings; protected List scopeMappings; protected List redirectUris; @@ -164,4 +165,12 @@ public class ApplicationRepresentation { public void setWebOrigins(List webOrigins) { this.webOrigins = webOrigins; } + + public String[] getDefaultRoles() { + return defaultRoles; + } + + public void setDefaultRoles(String[] defaultRoles) { + this.defaultRoles = defaultRoles; + } } diff --git a/model/api/src/main/java/org/keycloak/models/ApplicationModel.java b/model/api/src/main/java/org/keycloak/models/ApplicationModel.java index 05dedaf3cf..9a346f2532 100755 --- a/model/api/src/main/java/org/keycloak/models/ApplicationModel.java +++ b/model/api/src/main/java/org/keycloak/models/ApplicationModel.java @@ -34,4 +34,9 @@ public interface ApplicationModel extends RoleContainerModel, RoleMapperModel, S void setBaseUrl(String url); + List getDefaultRoles(); + + void addDefaultRole(String name); + + void updateDefaultRoles(String[] defaultRoles); } diff --git a/model/api/src/main/java/org/keycloak/models/Constants.java b/model/api/src/main/java/org/keycloak/models/Constants.java index 57002e5c0c..18adf6314e 100755 --- a/model/api/src/main/java/org/keycloak/models/Constants.java +++ b/model/api/src/main/java/org/keycloak/models/Constants.java @@ -13,6 +13,6 @@ public interface Constants { String WILDCARD_ROLE = "*"; String ACCOUNT_APPLICATION = "Account"; - String ACCOUNT_PROFILE_ROLE = "KEYCLOAK_ACCOUNT_PROFILE"; - String ACCOUNT_MANAGE_ROLE = "KEYCLOAK_ACCOUNT_MANAGE"; + String ACCOUNT_PROFILE_ROLE = "view-profile"; + String ACCOUNT_MANAGE_ROLE = "manage-account"; } diff --git a/model/api/src/main/java/org/keycloak/models/RealmModel.java b/model/api/src/main/java/org/keycloak/models/RealmModel.java index 5c1b468f87..2de3e58904 100755 --- a/model/api/src/main/java/org/keycloak/models/RealmModel.java +++ b/model/api/src/main/java/org/keycloak/models/RealmModel.java @@ -85,7 +85,7 @@ public interface RealmModel extends RoleContainerModel, RoleMapperModel, ScopeMa UserModel addUser(String username); - List getDefaultRoles(); + List getDefaultRoles(); void addDefaultRole(String name); diff --git a/model/picketlink/src/main/java/org/keycloak/models/picketlink/ApplicationAdapter.java b/model/picketlink/src/main/java/org/keycloak/models/picketlink/ApplicationAdapter.java index 8ad09eb50e..436b23ce8e 100755 --- a/model/picketlink/src/main/java/org/keycloak/models/picketlink/ApplicationAdapter.java +++ b/model/picketlink/src/main/java/org/keycloak/models/picketlink/ApplicationAdapter.java @@ -15,10 +15,7 @@ import org.picketlink.idm.model.sample.SampleModel; import org.picketlink.idm.query.IdentityQuery; import org.picketlink.idm.query.RelationshipQuery; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; +import java.util.*; /** * @author Bill Burke @@ -257,4 +254,44 @@ public class ApplicationAdapter implements ApplicationModel { return roles; } + @Override + public List getDefaultRoles() { + if ( applicationData.getDefaultRoles() != null) { + return Arrays.asList(applicationData.getDefaultRoles()); + } + else { + return Collections.emptyList(); + } + } + + @Override + public void addDefaultRole(String name) { + if (getRole(name) == null) { + addRole(name); + } + + String[] defaultRoles = applicationData.getDefaultRoles(); + if (defaultRoles == null) { + defaultRoles = new String[1]; + } else { + defaultRoles = Arrays.copyOf(defaultRoles, defaultRoles.length + 1); + } + defaultRoles[defaultRoles.length - 1] = name; + + applicationData.setDefaultRoles(defaultRoles); + updateApplication(); + } + + @Override + public void updateDefaultRoles(String[] defaultRoles) { + for (String name : defaultRoles) { + if (getRole(name) == null) { + addRole(name); + } + } + + applicationData.setDefaultRoles(defaultRoles); + updateApplication(); + } + } diff --git a/model/picketlink/src/main/java/org/keycloak/models/picketlink/RealmAdapter.java b/model/picketlink/src/main/java/org/keycloak/models/picketlink/RealmAdapter.java index d3268d2fa9..58c44b4051 100755 --- a/model/picketlink/src/main/java/org/keycloak/models/picketlink/RealmAdapter.java +++ b/model/picketlink/src/main/java/org/keycloak/models/picketlink/RealmAdapter.java @@ -29,13 +29,7 @@ import java.io.StringWriter; import java.security.PrivateKey; import java.security.PublicKey; import java.security.cert.X509Certificate; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.util.*; /** * Meant to be a per-request object @@ -754,17 +748,13 @@ public class RealmAdapter implements RealmModel { } @Override - public List getDefaultRoles() { - List defaultRoleModels = new ArrayList(); + public List getDefaultRoles() { if (realm.getDefaultRoles() != null) { - for (String name : realm.getDefaultRoles()) { - RoleAdapter role = getRole(name); - if (role != null) { - defaultRoleModels.add(role); - } - } + return Arrays.asList(realm.getDefaultRoles()); + } + else { + return Collections.emptyList(); } - return defaultRoleModels; } @Override diff --git a/model/picketlink/src/main/java/org/keycloak/models/picketlink/mappings/ApplicationData.java b/model/picketlink/src/main/java/org/keycloak/models/picketlink/mappings/ApplicationData.java index 8d5594ae74..5ce4aca2a6 100755 --- a/model/picketlink/src/main/java/org/keycloak/models/picketlink/mappings/ApplicationData.java +++ b/model/picketlink/src/main/java/org/keycloak/models/picketlink/mappings/ApplicationData.java @@ -15,6 +15,7 @@ public class ApplicationData extends AbstractPartition { private String managementUrl; private String baseUrl; private User resourceUser; + private String[] defaultRoles; public ApplicationData() { super(null); @@ -76,4 +77,13 @@ public class ApplicationData extends AbstractPartition { this.baseUrl = baseUrl; } + @AttributeProperty + public String[] getDefaultRoles() { + return defaultRoles; + } + + public void setDefaultRoles(String[] defaultRoles) { + this.defaultRoles = defaultRoles; + } + } diff --git a/model/picketlink/src/main/java/org/keycloak/models/picketlink/mappings/ApplicationEntity.java b/model/picketlink/src/main/java/org/keycloak/models/picketlink/mappings/ApplicationEntity.java index 0eddf7e230..0e8d23bfab 100755 --- a/model/picketlink/src/main/java/org/keycloak/models/picketlink/mappings/ApplicationEntity.java +++ b/model/picketlink/src/main/java/org/keycloak/models/picketlink/mappings/ApplicationEntity.java @@ -34,6 +34,9 @@ public class ApplicationEntity implements Serializable { @AttributeValue private String baseUrl; + @AttributeValue + private String[] defaultRoles; + @OneToOne @AttributeValue AccountTypeEntity resourceUser; @@ -94,4 +97,13 @@ public class ApplicationEntity implements Serializable { public void setResourceUser(AccountTypeEntity resourceUser) { this.resourceUser = resourceUser; } + + public String[] getDefaultRoles() { + return defaultRoles; + } + + public void setDefaultRoles(String[] defaultRoles) { + this.defaultRoles = defaultRoles; + } + } diff --git a/services/src/main/java/org/keycloak/services/managers/ApplicationManager.java b/services/src/main/java/org/keycloak/services/managers/ApplicationManager.java index 886f0dc570..fc854a376d 100755 --- a/services/src/main/java/org/keycloak/services/managers/ApplicationManager.java +++ b/services/src/main/java/org/keycloak/services/managers/ApplicationManager.java @@ -61,6 +61,11 @@ public class ApplicationManager { if (roleRep.getDescription() != null) role.setDescription(roleRep.getDescription()); } } + + if (resourceRep.getDefaultRoles() != null) { + applicationModel.updateDefaultRoles(resourceRep.getDefaultRoles()); + } + if (resourceRep.getRoleMappings() != null) { for (UserRoleMappingRepresentation mapping : resourceRep.getRoleMappings()) { UserModel user = realm.getUser(mapping.getUsername()); @@ -102,6 +107,10 @@ public class ApplicationManager { resource.setSurrogateAuthRequired(rep.isSurrogateAuthRequired()); resource.updateApplication(); + if (rep.getDefaultRoles() != null) { + resource.updateDefaultRoles(rep.getDefaultRoles()); + } + List redirectUris = rep.getRedirectUris(); if (redirectUris != null) { resource.getApplicationUser().setRedirectUris(new HashSet(redirectUris)); @@ -132,6 +141,10 @@ public class ApplicationManager { rep.setWebOrigins(new LinkedList(webOrigins)); } + if (!applicationModel.getDefaultRoles().isEmpty()) { + rep.setDefaultRoles((String[]) applicationModel.getDefaultRoles().toArray()); + } + return rep; } diff --git a/services/src/main/java/org/keycloak/services/managers/RealmManager.java b/services/src/main/java/org/keycloak/services/managers/RealmManager.java index 52f88f1c0e..017a08cbf6 100755 --- a/services/src/main/java/org/keycloak/services/managers/RealmManager.java +++ b/services/src/main/java/org/keycloak/services/managers/RealmManager.java @@ -110,8 +110,8 @@ public class RealmManager { ApplicationModel application = realm.getApplicationById(Constants.ACCOUNT_APPLICATION); if (application == null) { application = realm.addApplication(Constants.ACCOUNT_APPLICATION); - application.addRole(Constants.ACCOUNT_PROFILE_ROLE); - application.addRole(Constants.ACCOUNT_MANAGE_ROLE); + application.addDefaultRole(Constants.ACCOUNT_PROFILE_ROLE); + application.addDefaultRole(Constants.ACCOUNT_MANAGE_ROLE); UserCredentialModel password = new UserCredentialModel(); password.setType(UserCredentialModel.PASSWORD); @@ -429,13 +429,9 @@ public class RealmManager { ApplicationModel accountManagementApplication = realm.getApplicationNameMap().get(Constants.ACCOUNT_APPLICATION); rep.setAccountManagement(accountManagementApplication != null && accountManagementApplication.isEnabled()); - List defaultRoles = realm.getDefaultRoles(); - if (defaultRoles.size() > 0) { - String[] d = new String[defaultRoles.size()]; - for (int i = 0; i < d.length; i++) { - d[i] = defaultRoles.get(i).getName(); - } - rep.setDefaultRoles(d); + List defaultRoles = realm.getDefaultRoles(); + if (!defaultRoles.isEmpty()) { + rep.setDefaultRoles((String[]) realm.getDefaultRoles().toArray()); } List requiredCredentialModels = realm.getRequiredCredentials(); diff --git a/services/src/main/java/org/keycloak/services/managers/TokenManager.java b/services/src/main/java/org/keycloak/services/managers/TokenManager.java index 4b6f79eb6c..e7cb2ff95f 100755 --- a/services/src/main/java/org/keycloak/services/managers/TokenManager.java +++ b/services/src/main/java/org/keycloak/services/managers/TokenManager.java @@ -45,6 +45,7 @@ public class TokenManager { List realmRolesRequested = code.getRealmRolesRequested(); MultivaluedMap resourceRolesRequested = code.getResourceRolesRequested(); Set realmMapping = realm.getRoleMappingValues(user); + realmMapping.addAll(realm.getDefaultRoles()); if (realmMapping != null && realmMapping.size() > 0 && (scopeMap == null || scopeMap.containsKey("realm"))) { Set scope = realm.getScopeMappingValues(client); @@ -68,6 +69,8 @@ public class TokenManager { } for (ApplicationModel resource : realm.getApplications()) { Set mapping = resource.getRoleMappingValues(user); + mapping.addAll(resource.getDefaultRoles()); + if (mapping != null && mapping.size() > 0 && (scopeMap == null || scopeMap.containsKey(resource.getName()))) { Set scope = resource.getScopeMappingValues(client); if (scope.size() > 0) { @@ -185,6 +188,7 @@ public class TokenManager { } Set realmMapping = realm.getRoleMappingValues(user); + realmMapping.addAll(realm.getDefaultRoles()); if (realmMapping != null && realmMapping.size() > 0) { SkeletonKeyToken.Access access = new SkeletonKeyToken.Access(); @@ -196,6 +200,8 @@ public class TokenManager { if (resources != null) { for (ApplicationModel resource : resources) { Set mapping = resource.getRoleMappingValues(user); + mapping.addAll(resource.getDefaultRoles()); + if (mapping == null) continue; SkeletonKeyToken.Access access = token.addAccess(resource.getName()) .verifyCaller(resource.isSurrogateAuthRequired()); diff --git a/services/src/main/java/org/keycloak/services/resources/AccountService.java b/services/src/main/java/org/keycloak/services/resources/AccountService.java index 2abcf9969e..799b1011c3 100755 --- a/services/src/main/java/org/keycloak/services/resources/AccountService.java +++ b/services/src/main/java/org/keycloak/services/resources/AccountService.java @@ -21,13 +21,6 @@ */ package org.keycloak.services.resources; -import java.net.URI; -import java.util.List; - -import javax.ws.rs.*; -import javax.ws.rs.core.*; -import javax.ws.rs.ext.Providers; - import org.jboss.resteasy.jose.jws.JWSInput; import org.jboss.resteasy.jose.jws.crypto.RSAProvider; import org.jboss.resteasy.logging.Logger; @@ -49,6 +42,12 @@ import org.keycloak.services.resources.flows.Urls; import org.keycloak.services.validation.Validation; import org.picketlink.idm.credential.util.TimeBasedOTP; +import javax.ws.rs.*; +import javax.ws.rs.core.*; +import javax.ws.rs.ext.Providers; +import java.net.URI; +import java.util.List; + /** * @author Stian Thorgersen */ @@ -87,12 +86,19 @@ public class AccountService { private Response forwardToPage(String path, String template) { AuthenticationManager.Auth auth = getAuth(false); if (auth != null) { + if (!hasAccess(auth)) { + return noAccess(); + } return Flows.forms(realm, request, uriInfo).setUser(auth.getUser()).forwardToForm(template); } else { return login(path); } } + private Response noAccess() { + return Flows.forms(realm, request, uriInfo).setError("No access").forwardToErrorPage(); + } + @Path("/") @OPTIONS public Response accountPreflight() { @@ -108,9 +114,8 @@ public class AccountService { } else if (types.contains(MediaType.APPLICATION_JSON_TYPE)) { AuthenticationManager.Auth auth = getAuth(true); if (!hasAccess(auth, Constants.ACCOUNT_PROFILE_ROLE)) { - throw new ForbiddenException(); + return Response.status(Response.Status.FORBIDDEN).build(); } - return Cors.add(request, Response.ok(RealmManager.toRepresentation(auth.getUser()))).auth().allowedOrigins(auth.getClient()).build(); } else { return Response.notAcceptable(Variant.VariantListBuilder.newInstance().mediaTypes(MediaType.TEXT_HTML_TYPE, MediaType.APPLICATION_JSON_TYPE).build()).build(); @@ -146,6 +151,10 @@ public class AccountService { @Consumes(MediaType.APPLICATION_FORM_URLENCODED) public Response processAccountUpdate(final MultivaluedMap formData) { AuthenticationManager.Auth auth = getAuth(true); + if (!hasAccess(auth)) { + return noAccess(); + } + UserModel user = auth.getUser(); String error = Validation.validateUpdateProfileForm(formData); @@ -165,6 +174,10 @@ public class AccountService { @GET public Response processTotpRemove() { AuthenticationManager.Auth auth = getAuth(true); + if (!hasAccess(auth)) { + return noAccess(); + } + UserModel user = auth.getUser(); user.setTotp(false); @@ -177,6 +190,10 @@ public class AccountService { @Consumes(MediaType.APPLICATION_FORM_URLENCODED) public Response processTotpUpdate(final MultivaluedMap formData) { AuthenticationManager.Auth auth = getAuth(true); + if (!hasAccess(auth)) { + return noAccess(); + } + UserModel user = auth.getUser(); String totp = formData.getFirst("totp"); @@ -205,6 +222,10 @@ public class AccountService { @Consumes(MediaType.APPLICATION_FORM_URLENCODED) public Response processPasswordUpdate(final MultivaluedMap formData) { AuthenticationManager.Auth auth = getAuth(true); + if (!hasAccess(auth)) { + return noAccess(); + } + UserModel user = auth.getUser(); FormFlows forms = Flows.forms(realm, request, uriInfo).setUser(user); @@ -336,30 +357,30 @@ public class AccountService { return oauth.redirect(uriInfo, accountUri.toString(), path); } - private AuthenticationManager.Auth getAuth(boolean required) { + private AuthenticationManager.Auth getAuth(boolean error) { AuthenticationManager.Auth auth = authManager.authenticateAccountIdentity(realm, uriInfo, headers); - if (auth == null && required) { + if (auth == null && error) { throw new ForbiddenException(); } return auth; } - private boolean hasAccess(AuthenticationManager.Auth auth, String requiredRole) { + private boolean hasAccess(AuthenticationManager.Auth auth) { + return hasAccess(auth, null); + } + + private boolean hasAccess(AuthenticationManager.Auth auth, String role) { UserModel client = auth.getClient(); - if (realm.hasRole(client, Constants.APPLICATION_ROLE)) { - return true; - } - - SkeletonKeyToken token = auth.getToken(); - SkeletonKeyToken.Access access = token.getResourceAccess(application.getName()); - - if (access != null) { - if (access.isUserInRole(Constants.ACCOUNT_MANAGE_ROLE)) { + // Tokens from cookies don't have roles + if (hasRole(client, Constants.ACCOUNT_MANAGE_ROLE) || (role != null && hasRole(client, role))) { return true; } + } - if (access.isUserInRole(Constants.ACCOUNT_PROFILE_ROLE)) { + SkeletonKeyToken.Access access = auth.getToken().getResourceAccess(application.getName()); + if (access != null) { + if (access.isUserInRole(Constants.ACCOUNT_MANAGE_ROLE) || (role != null && access.isUserInRole(role))) { return true; } } @@ -367,4 +388,11 @@ public class AccountService { return false; } + private boolean hasRole(UserModel user, String role) { + if (application.getDefaultRoles().contains(role)) { + return true; + } + return application.hasRole(user, role); + } + } diff --git a/services/src/main/java/org/keycloak/services/resources/SocialResource.java b/services/src/main/java/org/keycloak/services/resources/SocialResource.java index 4a2ab82520..573da77f96 100755 --- a/services/src/main/java/org/keycloak/services/resources/SocialResource.java +++ b/services/src/main/java/org/keycloak/services/resources/SocialResource.java @@ -176,10 +176,6 @@ public class SocialResource { } realm.addSocialLink(user, socialLink); - - for (RoleModel role : realm.getDefaultRoles()) { - realm.grantRole(user, role); - } } else { // Redirect user to registration screen with prefilled data from social provider MultivaluedMap formData = fillRegistrationFormWithSocialData(socialUser); diff --git a/services/src/main/java/org/keycloak/services/resources/TokenService.java b/services/src/main/java/org/keycloak/services/resources/TokenService.java index 7388b61667..c8250049d3 100755 --- a/services/src/main/java/org/keycloak/services/resources/TokenService.java +++ b/services/src/main/java/org/keycloak/services/resources/TokenService.java @@ -309,10 +309,6 @@ public class TokenService { realm.updateCredential(user, credentials); } - for (RoleModel role : realm.getDefaultRoles()) { - realm.grantRole(user, role); - } - return null; } diff --git a/services/src/test/java/org/keycloak/test/AdapterTest.java b/services/src/test/java/org/keycloak/test/AdapterTest.java index 22c38b3ef4..d6b178af22 100755 --- a/services/src/test/java/org/keycloak/test/AdapterTest.java +++ b/services/src/test/java/org/keycloak/test/AdapterTest.java @@ -73,7 +73,7 @@ public class AdapterTest extends AbstractKeycloakTest { Assert.assertEquals(realmModel.getPublicKeyPem(), "0234234"); Assert.assertEquals(realmModel.isAutomaticRegistrationAfterSocialLogin(), true); Assert.assertEquals(1, realmModel.getDefaultRoles().size()); - Assert.assertEquals("foo", realmModel.getDefaultRoles().get(0).getName()); + Assert.assertEquals("foo", realmModel.getDefaultRoles().get(0)); } @Test @@ -102,7 +102,7 @@ public class AdapterTest extends AbstractKeycloakTest { Assert.assertEquals(realmModel.getPublicKeyPem(), "0234234"); Assert.assertEquals(realmModel.isAutomaticRegistrationAfterSocialLogin(), true); Assert.assertEquals(1, realmModel.getDefaultRoles().size()); - Assert.assertEquals("foo", realmModel.getDefaultRoles().get(0).getName()); + Assert.assertEquals("foo", realmModel.getDefaultRoles().get(0)); String id = realmModel.getId(); System.out.println("id: " + id); diff --git a/services/src/test/java/org/keycloak/test/ApplicationModelTest.java b/services/src/test/java/org/keycloak/test/ApplicationModelTest.java index 57c3ba5004..5d0de1a990 100644 --- a/services/src/test/java/org/keycloak/test/ApplicationModelTest.java +++ b/services/src/test/java/org/keycloak/test/ApplicationModelTest.java @@ -42,6 +42,8 @@ public class ApplicationModelTest extends AbstractKeycloakServerTest { application.setName("app-name"); application.addRole("role-1"); application.addRole("role-2"); + application.addDefaultRole("role-1"); + application.addDefaultRole("role-2"); application.getApplicationUser().addRedirectUri("redirect-1"); application.getApplicationUser().addRedirectUri("redirect-2"); @@ -80,6 +82,7 @@ public class ApplicationModelTest extends AbstractKeycloakServerTest { Assert.assertEquals(expected.getName(), actual.getName()); Assert.assertEquals(expected.getBaseUrl(), actual.getBaseUrl()); Assert.assertEquals(expected.getManagementUrl(), actual.getManagementUrl()); + Assert.assertEquals(expected.getDefaultRoles(), actual.getDefaultRoles()); UserModel auser = actual.getApplicationUser(); UserModel euser = expected.getApplicationUser(); diff --git a/services/src/test/java/org/keycloak/test/ModelTest.java b/services/src/test/java/org/keycloak/test/ModelTest.java index 9f9400c55a..9b244bea30 100755 --- a/services/src/test/java/org/keycloak/test/ModelTest.java +++ b/services/src/test/java/org/keycloak/test/ModelTest.java @@ -86,7 +86,7 @@ public class ModelTest extends AbstractKeycloakServerTest { Assert.assertEquals(expected.getPublicKeyPem(), actual.getPublicKeyPem()); Assert.assertEquals(expected.getPrivateKeyPem(), actual.getPrivateKeyPem()); - assertEquals(expected.getDefaultRoles(), actual.getDefaultRoles()); + Assert.assertEquals(expected.getDefaultRoles(), actual.getDefaultRoles()); Assert.assertEquals(expected.getSmtpConfig(), actual.getSmtpConfig()); Assert.assertEquals(expected.getSocialConfig(), actual.getSocialConfig()); diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/account/ProfileTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/account/ProfileTest.java index cc5144de54..9891af00f0 100644 --- a/testsuite/integration/src/test/java/org/keycloak/testsuite/account/ProfileTest.java +++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/account/ProfileTest.java @@ -29,6 +29,8 @@ import javax.ws.rs.core.MediaType; import javax.ws.rs.core.UriBuilder; import java.io.IOException; import java.net.URI; +import java.util.Collections; +import java.util.List; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; @@ -51,17 +53,13 @@ public class ProfileTest { ApplicationModel accountApp = appRealm.getApplicationNameMap().get(org.keycloak.models.Constants.ACCOUNT_APPLICATION); - accountApp.grantRole(user, accountApp.getRole(org.keycloak.models.Constants.ACCOUNT_PROFILE_ROLE)); - accountApp.grantRole(user, accountApp.getRole(org.keycloak.models.Constants.ACCOUNT_MANAGE_ROLE)); + ApplicationModel app = appRealm.getApplicationNameMap().get("test-app"); + accountApp.addScopeMapping(app.getApplicationUser(), org.keycloak.models.Constants.ACCOUNT_PROFILE_ROLE); + + app.getApplicationUser().addWebOrigin("http://localtest.me:8081"); UserModel thirdParty = appRealm.getUser("third-party"); accountApp.addScopeMapping(thirdParty, org.keycloak.models.Constants.ACCOUNT_PROFILE_ROLE); - - for (ApplicationModel app : appRealm.getApplications()) { - if (app.getName().equals("test-app")) { - app.getApplicationUser().addWebOrigin("http://localtest.me:8081"); - } - } } }); @@ -83,6 +81,8 @@ public class ProfileTest { @WebResource protected OAuthGrantPage grantPage; + private List defaultRoles; + @Test public void getProfile() throws Exception { oauth.doLogin("test-user@localhost", "password"); @@ -119,7 +119,7 @@ public class ProfileTest { } @Test - public void getProfileCorsInvalidOrigin() throws Exception { + public void getProfileCorsInvalidOrigin() throws Exception { oauth.doLogin("test-user@localhost", "password"); String code = oauth.getCurrentQuery().get("code"); @@ -152,6 +152,35 @@ public class ProfileTest { assertEquals(403, response.getStatusLine().getStatusCode()); } + @Test + public void getProfileNoAccess() throws Exception { + try { + keycloakRule.configure(new KeycloakRule.KeycloakSetup() { + @Override + public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) { + ApplicationModel app = appRealm.getApplicationNameMap().get(org.keycloak.models.Constants.ACCOUNT_APPLICATION); + defaultRoles = app.getDefaultRoles(); + app.updateDefaultRoles(new String[0]); + } + }); + + oauth.doLogin("test-user@localhost", "password"); + + String code = oauth.getCurrentQuery().get("code"); + String token = oauth.doAccessTokenRequest(code, "password").getAccessToken(); + + HttpResponse response = doGetProfile(token, null); + assertEquals(403, response.getStatusLine().getStatusCode()); + } finally { + keycloakRule.configure(new KeycloakRule.KeycloakSetup() { + @Override + public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) { + appRealm.getApplicationNameMap().get(org.keycloak.models.Constants.ACCOUNT_APPLICATION).updateDefaultRoles((String[]) defaultRoles.toArray()); + } + }); + } + } + @Test public void getProfileOAuthClient() throws Exception { oauth.addScope(org.keycloak.models.Constants.ACCOUNT_APPLICATION, org.keycloak.models.Constants.ACCOUNT_PROFILE_ROLE); @@ -209,7 +238,7 @@ public class ProfileTest { sb.append("req.send(null);\n"); sb.append("return req.status + '///' + req.responseText;\n"); - JavascriptExecutor js = (JavascriptExecutor) driver; + JavascriptExecutor js = (JavascriptExecutor) driver; String response = (String) js.executeScript(sb.toString()); return response.split("///"); } diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/AccountTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/AccountTest.java index 5b1a82725d..f7bc8112d6 100755 --- a/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/AccountTest.java +++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/AccountTest.java @@ -21,19 +21,14 @@ */ package org.keycloak.testsuite.forms; +import org.apache.http.HttpResponse; import org.junit.*; +import org.keycloak.models.*; import org.keycloak.representations.idm.CredentialRepresentation; import org.keycloak.services.managers.RealmManager; -import org.keycloak.models.RealmModel; -import org.keycloak.models.UserCredentialModel; -import org.keycloak.models.UserModel; import org.keycloak.testsuite.OAuthClient; -import org.keycloak.testsuite.pages.AccountPasswordPage; -import org.keycloak.testsuite.pages.AccountTotpPage; -import org.keycloak.testsuite.pages.AccountUpdateProfilePage; -import org.keycloak.testsuite.pages.AppPage; +import org.keycloak.testsuite.pages.*; import org.keycloak.testsuite.pages.AppPage.RequestType; -import org.keycloak.testsuite.pages.LoginPage; import org.keycloak.testsuite.rule.KeycloakRule; import org.keycloak.testsuite.rule.KeycloakRule.KeycloakSetup; import org.keycloak.testsuite.rule.WebResource; @@ -43,6 +38,10 @@ import org.openqa.selenium.WebElement; import org.openqa.selenium.support.FindBy; import org.picketlink.idm.credential.util.TimeBasedOTP; +import java.util.List; + +import static org.junit.Assert.assertEquals; + /** * @author Stian Thorgersen */ @@ -75,8 +74,13 @@ public class AccountTest { @WebResource protected AccountTotpPage totpPage; + @WebResource + protected ErrorPage errorPage; + private TimeBasedOTP totp = new TimeBasedOTP(); + private List defaultRoles; + @After public void after() { keycloakRule.configure(new KeycloakSetup() { @@ -183,4 +187,31 @@ public class AccountTest { Assert.assertTrue(driver.getPageSource().contains("Remove Google")); } + @Test + public void changeProfileNoAccess() throws Exception { + try { + keycloakRule.configure(new KeycloakRule.KeycloakSetup() { + @Override + public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) { + ApplicationModel app = appRealm.getApplicationNameMap().get(Constants.ACCOUNT_APPLICATION); + defaultRoles = app.getDefaultRoles(); + app.updateDefaultRoles(new String[0]); + } + }); + + profilePage.open(); + loginPage.login("test-user@localhost", "password"); + + Assert.assertTrue(errorPage.isCurrent()); + Assert.assertEquals("No access", errorPage.getError()); + } finally { + keycloakRule.configure(new KeycloakRule.KeycloakSetup() { + @Override + public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) { + appRealm.getApplicationNameMap().get(org.keycloak.models.Constants.ACCOUNT_APPLICATION).updateDefaultRoles((String[]) defaultRoles.toArray()); + } + }); + } + } + } diff --git a/testsuite/performance/src/test/java/org/keycloak/testsuite/performance/CreateUsersWorker.java b/testsuite/performance/src/test/java/org/keycloak/testsuite/performance/CreateUsersWorker.java index 29bd33cc92..67d2ca6826 100644 --- a/testsuite/performance/src/test/java/org/keycloak/testsuite/performance/CreateUsersWorker.java +++ b/testsuite/performance/src/test/java/org/keycloak/testsuite/performance/CreateUsersWorker.java @@ -78,13 +78,6 @@ public class CreateUsersWorker implements Worker { user.setEmail(username + "@email.com"); } - // Adding default roles of realm to user - if (addDefaultRoles) { - for (RoleModel role : realm.getDefaultRoles()) { - realm.grantRole(user, role); - } - } - // Creating password (will be same as username) if (addPassword) { UserCredentialModel password = new UserCredentialModel();