Added support for default application roles. Added authz to account, user (or client if oauth) is required to have role manage-account to manage their account, this is a default role for the Account application.
This commit is contained in:
parent
97792b7e1d
commit
d083909136
20 changed files with 244 additions and 90 deletions
|
@ -18,6 +18,7 @@ public class ApplicationRepresentation {
|
||||||
protected boolean enabled;
|
protected boolean enabled;
|
||||||
protected List<CredentialRepresentation> credentials;
|
protected List<CredentialRepresentation> credentials;
|
||||||
protected List<RoleRepresentation> roles;
|
protected List<RoleRepresentation> roles;
|
||||||
|
protected String[] defaultRoles;
|
||||||
protected List<UserRoleMappingRepresentation> roleMappings;
|
protected List<UserRoleMappingRepresentation> roleMappings;
|
||||||
protected List<ScopeMappingRepresentation> scopeMappings;
|
protected List<ScopeMappingRepresentation> scopeMappings;
|
||||||
protected List<String> redirectUris;
|
protected List<String> redirectUris;
|
||||||
|
@ -164,4 +165,12 @@ public class ApplicationRepresentation {
|
||||||
public void setWebOrigins(List<String> webOrigins) {
|
public void setWebOrigins(List<String> webOrigins) {
|
||||||
this.webOrigins = webOrigins;
|
this.webOrigins = webOrigins;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String[] getDefaultRoles() {
|
||||||
|
return defaultRoles;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDefaultRoles(String[] defaultRoles) {
|
||||||
|
this.defaultRoles = defaultRoles;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,4 +34,9 @@ public interface ApplicationModel extends RoleContainerModel, RoleMapperModel, S
|
||||||
|
|
||||||
void setBaseUrl(String url);
|
void setBaseUrl(String url);
|
||||||
|
|
||||||
|
List<String> getDefaultRoles();
|
||||||
|
|
||||||
|
void addDefaultRole(String name);
|
||||||
|
|
||||||
|
void updateDefaultRoles(String[] defaultRoles);
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,6 @@ public interface Constants {
|
||||||
String WILDCARD_ROLE = "*";
|
String WILDCARD_ROLE = "*";
|
||||||
|
|
||||||
String ACCOUNT_APPLICATION = "Account";
|
String ACCOUNT_APPLICATION = "Account";
|
||||||
String ACCOUNT_PROFILE_ROLE = "KEYCLOAK_ACCOUNT_PROFILE";
|
String ACCOUNT_PROFILE_ROLE = "view-profile";
|
||||||
String ACCOUNT_MANAGE_ROLE = "KEYCLOAK_ACCOUNT_MANAGE";
|
String ACCOUNT_MANAGE_ROLE = "manage-account";
|
||||||
}
|
}
|
||||||
|
|
|
@ -85,7 +85,7 @@ public interface RealmModel extends RoleContainerModel, RoleMapperModel, ScopeMa
|
||||||
|
|
||||||
UserModel addUser(String username);
|
UserModel addUser(String username);
|
||||||
|
|
||||||
List<RoleModel> getDefaultRoles();
|
List<String> getDefaultRoles();
|
||||||
|
|
||||||
void addDefaultRole(String name);
|
void addDefaultRole(String name);
|
||||||
|
|
||||||
|
|
|
@ -15,10 +15,7 @@ import org.picketlink.idm.model.sample.SampleModel;
|
||||||
import org.picketlink.idm.query.IdentityQuery;
|
import org.picketlink.idm.query.IdentityQuery;
|
||||||
import org.picketlink.idm.query.RelationshipQuery;
|
import org.picketlink.idm.query.RelationshipQuery;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
|
@ -257,4 +254,44 @@ public class ApplicationAdapter implements ApplicationModel {
|
||||||
return roles;
|
return roles;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> 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();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,13 +29,7 @@ import java.io.StringWriter;
|
||||||
import java.security.PrivateKey;
|
import java.security.PrivateKey;
|
||||||
import java.security.PublicKey;
|
import java.security.PublicKey;
|
||||||
import java.security.cert.X509Certificate;
|
import java.security.cert.X509Certificate;
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Meant to be a per-request object
|
* Meant to be a per-request object
|
||||||
|
@ -754,17 +748,13 @@ public class RealmAdapter implements RealmModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<RoleModel> getDefaultRoles() {
|
public List<String> getDefaultRoles() {
|
||||||
List<RoleModel> defaultRoleModels = new ArrayList<RoleModel>();
|
|
||||||
if (realm.getDefaultRoles() != null) {
|
if (realm.getDefaultRoles() != null) {
|
||||||
for (String name : realm.getDefaultRoles()) {
|
return Arrays.asList(realm.getDefaultRoles());
|
||||||
RoleAdapter role = getRole(name);
|
}
|
||||||
if (role != null) {
|
else {
|
||||||
defaultRoleModels.add(role);
|
return Collections.emptyList();
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return defaultRoleModels;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -15,6 +15,7 @@ public class ApplicationData extends AbstractPartition {
|
||||||
private String managementUrl;
|
private String managementUrl;
|
||||||
private String baseUrl;
|
private String baseUrl;
|
||||||
private User resourceUser;
|
private User resourceUser;
|
||||||
|
private String[] defaultRoles;
|
||||||
|
|
||||||
public ApplicationData() {
|
public ApplicationData() {
|
||||||
super(null);
|
super(null);
|
||||||
|
@ -76,4 +77,13 @@ public class ApplicationData extends AbstractPartition {
|
||||||
this.baseUrl = baseUrl;
|
this.baseUrl = baseUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@AttributeProperty
|
||||||
|
public String[] getDefaultRoles() {
|
||||||
|
return defaultRoles;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDefaultRoles(String[] defaultRoles) {
|
||||||
|
this.defaultRoles = defaultRoles;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,6 +34,9 @@ public class ApplicationEntity implements Serializable {
|
||||||
@AttributeValue
|
@AttributeValue
|
||||||
private String baseUrl;
|
private String baseUrl;
|
||||||
|
|
||||||
|
@AttributeValue
|
||||||
|
private String[] defaultRoles;
|
||||||
|
|
||||||
@OneToOne
|
@OneToOne
|
||||||
@AttributeValue
|
@AttributeValue
|
||||||
AccountTypeEntity resourceUser;
|
AccountTypeEntity resourceUser;
|
||||||
|
@ -94,4 +97,13 @@ public class ApplicationEntity implements Serializable {
|
||||||
public void setResourceUser(AccountTypeEntity resourceUser) {
|
public void setResourceUser(AccountTypeEntity resourceUser) {
|
||||||
this.resourceUser = resourceUser;
|
this.resourceUser = resourceUser;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String[] getDefaultRoles() {
|
||||||
|
return defaultRoles;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDefaultRoles(String[] defaultRoles) {
|
||||||
|
this.defaultRoles = defaultRoles;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,6 +61,11 @@ public class ApplicationManager {
|
||||||
if (roleRep.getDescription() != null) role.setDescription(roleRep.getDescription());
|
if (roleRep.getDescription() != null) role.setDescription(roleRep.getDescription());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (resourceRep.getDefaultRoles() != null) {
|
||||||
|
applicationModel.updateDefaultRoles(resourceRep.getDefaultRoles());
|
||||||
|
}
|
||||||
|
|
||||||
if (resourceRep.getRoleMappings() != null) {
|
if (resourceRep.getRoleMappings() != null) {
|
||||||
for (UserRoleMappingRepresentation mapping : resourceRep.getRoleMappings()) {
|
for (UserRoleMappingRepresentation mapping : resourceRep.getRoleMappings()) {
|
||||||
UserModel user = realm.getUser(mapping.getUsername());
|
UserModel user = realm.getUser(mapping.getUsername());
|
||||||
|
@ -102,6 +107,10 @@ public class ApplicationManager {
|
||||||
resource.setSurrogateAuthRequired(rep.isSurrogateAuthRequired());
|
resource.setSurrogateAuthRequired(rep.isSurrogateAuthRequired());
|
||||||
resource.updateApplication();
|
resource.updateApplication();
|
||||||
|
|
||||||
|
if (rep.getDefaultRoles() != null) {
|
||||||
|
resource.updateDefaultRoles(rep.getDefaultRoles());
|
||||||
|
}
|
||||||
|
|
||||||
List<String> redirectUris = rep.getRedirectUris();
|
List<String> redirectUris = rep.getRedirectUris();
|
||||||
if (redirectUris != null) {
|
if (redirectUris != null) {
|
||||||
resource.getApplicationUser().setRedirectUris(new HashSet<String>(redirectUris));
|
resource.getApplicationUser().setRedirectUris(new HashSet<String>(redirectUris));
|
||||||
|
@ -132,6 +141,10 @@ public class ApplicationManager {
|
||||||
rep.setWebOrigins(new LinkedList<String>(webOrigins));
|
rep.setWebOrigins(new LinkedList<String>(webOrigins));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!applicationModel.getDefaultRoles().isEmpty()) {
|
||||||
|
rep.setDefaultRoles((String[]) applicationModel.getDefaultRoles().toArray());
|
||||||
|
}
|
||||||
|
|
||||||
return rep;
|
return rep;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -110,8 +110,8 @@ public class RealmManager {
|
||||||
ApplicationModel application = realm.getApplicationById(Constants.ACCOUNT_APPLICATION);
|
ApplicationModel application = realm.getApplicationById(Constants.ACCOUNT_APPLICATION);
|
||||||
if (application == null) {
|
if (application == null) {
|
||||||
application = realm.addApplication(Constants.ACCOUNT_APPLICATION);
|
application = realm.addApplication(Constants.ACCOUNT_APPLICATION);
|
||||||
application.addRole(Constants.ACCOUNT_PROFILE_ROLE);
|
application.addDefaultRole(Constants.ACCOUNT_PROFILE_ROLE);
|
||||||
application.addRole(Constants.ACCOUNT_MANAGE_ROLE);
|
application.addDefaultRole(Constants.ACCOUNT_MANAGE_ROLE);
|
||||||
|
|
||||||
UserCredentialModel password = new UserCredentialModel();
|
UserCredentialModel password = new UserCredentialModel();
|
||||||
password.setType(UserCredentialModel.PASSWORD);
|
password.setType(UserCredentialModel.PASSWORD);
|
||||||
|
@ -429,13 +429,9 @@ public class RealmManager {
|
||||||
ApplicationModel accountManagementApplication = realm.getApplicationNameMap().get(Constants.ACCOUNT_APPLICATION);
|
ApplicationModel accountManagementApplication = realm.getApplicationNameMap().get(Constants.ACCOUNT_APPLICATION);
|
||||||
rep.setAccountManagement(accountManagementApplication != null && accountManagementApplication.isEnabled());
|
rep.setAccountManagement(accountManagementApplication != null && accountManagementApplication.isEnabled());
|
||||||
|
|
||||||
List<RoleModel> defaultRoles = realm.getDefaultRoles();
|
List<String> defaultRoles = realm.getDefaultRoles();
|
||||||
if (defaultRoles.size() > 0) {
|
if (!defaultRoles.isEmpty()) {
|
||||||
String[] d = new String[defaultRoles.size()];
|
rep.setDefaultRoles((String[]) realm.getDefaultRoles().toArray());
|
||||||
for (int i = 0; i < d.length; i++) {
|
|
||||||
d[i] = defaultRoles.get(i).getName();
|
|
||||||
}
|
|
||||||
rep.setDefaultRoles(d);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
List<RequiredCredentialModel> requiredCredentialModels = realm.getRequiredCredentials();
|
List<RequiredCredentialModel> requiredCredentialModels = realm.getRequiredCredentials();
|
||||||
|
|
|
@ -45,6 +45,7 @@ public class TokenManager {
|
||||||
List<RoleModel> realmRolesRequested = code.getRealmRolesRequested();
|
List<RoleModel> realmRolesRequested = code.getRealmRolesRequested();
|
||||||
MultivaluedMap<String, RoleModel> resourceRolesRequested = code.getResourceRolesRequested();
|
MultivaluedMap<String, RoleModel> resourceRolesRequested = code.getResourceRolesRequested();
|
||||||
Set<String> realmMapping = realm.getRoleMappingValues(user);
|
Set<String> realmMapping = realm.getRoleMappingValues(user);
|
||||||
|
realmMapping.addAll(realm.getDefaultRoles());
|
||||||
|
|
||||||
if (realmMapping != null && realmMapping.size() > 0 && (scopeMap == null || scopeMap.containsKey("realm"))) {
|
if (realmMapping != null && realmMapping.size() > 0 && (scopeMap == null || scopeMap.containsKey("realm"))) {
|
||||||
Set<String> scope = realm.getScopeMappingValues(client);
|
Set<String> scope = realm.getScopeMappingValues(client);
|
||||||
|
@ -68,6 +69,8 @@ public class TokenManager {
|
||||||
}
|
}
|
||||||
for (ApplicationModel resource : realm.getApplications()) {
|
for (ApplicationModel resource : realm.getApplications()) {
|
||||||
Set<String> mapping = resource.getRoleMappingValues(user);
|
Set<String> mapping = resource.getRoleMappingValues(user);
|
||||||
|
mapping.addAll(resource.getDefaultRoles());
|
||||||
|
|
||||||
if (mapping != null && mapping.size() > 0 && (scopeMap == null || scopeMap.containsKey(resource.getName()))) {
|
if (mapping != null && mapping.size() > 0 && (scopeMap == null || scopeMap.containsKey(resource.getName()))) {
|
||||||
Set<String> scope = resource.getScopeMappingValues(client);
|
Set<String> scope = resource.getScopeMappingValues(client);
|
||||||
if (scope.size() > 0) {
|
if (scope.size() > 0) {
|
||||||
|
@ -185,6 +188,7 @@ public class TokenManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
Set<String> realmMapping = realm.getRoleMappingValues(user);
|
Set<String> realmMapping = realm.getRoleMappingValues(user);
|
||||||
|
realmMapping.addAll(realm.getDefaultRoles());
|
||||||
|
|
||||||
if (realmMapping != null && realmMapping.size() > 0) {
|
if (realmMapping != null && realmMapping.size() > 0) {
|
||||||
SkeletonKeyToken.Access access = new SkeletonKeyToken.Access();
|
SkeletonKeyToken.Access access = new SkeletonKeyToken.Access();
|
||||||
|
@ -196,6 +200,8 @@ public class TokenManager {
|
||||||
if (resources != null) {
|
if (resources != null) {
|
||||||
for (ApplicationModel resource : resources) {
|
for (ApplicationModel resource : resources) {
|
||||||
Set<String> mapping = resource.getRoleMappingValues(user);
|
Set<String> mapping = resource.getRoleMappingValues(user);
|
||||||
|
mapping.addAll(resource.getDefaultRoles());
|
||||||
|
|
||||||
if (mapping == null) continue;
|
if (mapping == null) continue;
|
||||||
SkeletonKeyToken.Access access = token.addAccess(resource.getName())
|
SkeletonKeyToken.Access access = token.addAccess(resource.getName())
|
||||||
.verifyCaller(resource.isSurrogateAuthRequired());
|
.verifyCaller(resource.isSurrogateAuthRequired());
|
||||||
|
|
|
@ -21,13 +21,6 @@
|
||||||
*/
|
*/
|
||||||
package org.keycloak.services.resources;
|
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.JWSInput;
|
||||||
import org.jboss.resteasy.jose.jws.crypto.RSAProvider;
|
import org.jboss.resteasy.jose.jws.crypto.RSAProvider;
|
||||||
import org.jboss.resteasy.logging.Logger;
|
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.keycloak.services.validation.Validation;
|
||||||
import org.picketlink.idm.credential.util.TimeBasedOTP;
|
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 <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||||
*/
|
*/
|
||||||
|
@ -87,12 +86,19 @@ public class AccountService {
|
||||||
private Response forwardToPage(String path, String template) {
|
private Response forwardToPage(String path, String template) {
|
||||||
AuthenticationManager.Auth auth = getAuth(false);
|
AuthenticationManager.Auth auth = getAuth(false);
|
||||||
if (auth != null) {
|
if (auth != null) {
|
||||||
|
if (!hasAccess(auth)) {
|
||||||
|
return noAccess();
|
||||||
|
}
|
||||||
return Flows.forms(realm, request, uriInfo).setUser(auth.getUser()).forwardToForm(template);
|
return Flows.forms(realm, request, uriInfo).setUser(auth.getUser()).forwardToForm(template);
|
||||||
} else {
|
} else {
|
||||||
return login(path);
|
return login(path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Response noAccess() {
|
||||||
|
return Flows.forms(realm, request, uriInfo).setError("No access").forwardToErrorPage();
|
||||||
|
}
|
||||||
|
|
||||||
@Path("/")
|
@Path("/")
|
||||||
@OPTIONS
|
@OPTIONS
|
||||||
public Response accountPreflight() {
|
public Response accountPreflight() {
|
||||||
|
@ -108,9 +114,8 @@ public class AccountService {
|
||||||
} else if (types.contains(MediaType.APPLICATION_JSON_TYPE)) {
|
} else if (types.contains(MediaType.APPLICATION_JSON_TYPE)) {
|
||||||
AuthenticationManager.Auth auth = getAuth(true);
|
AuthenticationManager.Auth auth = getAuth(true);
|
||||||
if (!hasAccess(auth, Constants.ACCOUNT_PROFILE_ROLE)) {
|
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();
|
return Cors.add(request, Response.ok(RealmManager.toRepresentation(auth.getUser()))).auth().allowedOrigins(auth.getClient()).build();
|
||||||
} else {
|
} else {
|
||||||
return Response.notAcceptable(Variant.VariantListBuilder.newInstance().mediaTypes(MediaType.TEXT_HTML_TYPE, MediaType.APPLICATION_JSON_TYPE).build()).build();
|
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)
|
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
|
||||||
public Response processAccountUpdate(final MultivaluedMap<String, String> formData) {
|
public Response processAccountUpdate(final MultivaluedMap<String, String> formData) {
|
||||||
AuthenticationManager.Auth auth = getAuth(true);
|
AuthenticationManager.Auth auth = getAuth(true);
|
||||||
|
if (!hasAccess(auth)) {
|
||||||
|
return noAccess();
|
||||||
|
}
|
||||||
|
|
||||||
UserModel user = auth.getUser();
|
UserModel user = auth.getUser();
|
||||||
|
|
||||||
String error = Validation.validateUpdateProfileForm(formData);
|
String error = Validation.validateUpdateProfileForm(formData);
|
||||||
|
@ -165,6 +174,10 @@ public class AccountService {
|
||||||
@GET
|
@GET
|
||||||
public Response processTotpRemove() {
|
public Response processTotpRemove() {
|
||||||
AuthenticationManager.Auth auth = getAuth(true);
|
AuthenticationManager.Auth auth = getAuth(true);
|
||||||
|
if (!hasAccess(auth)) {
|
||||||
|
return noAccess();
|
||||||
|
}
|
||||||
|
|
||||||
UserModel user = auth.getUser();
|
UserModel user = auth.getUser();
|
||||||
|
|
||||||
user.setTotp(false);
|
user.setTotp(false);
|
||||||
|
@ -177,6 +190,10 @@ public class AccountService {
|
||||||
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
|
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
|
||||||
public Response processTotpUpdate(final MultivaluedMap<String, String> formData) {
|
public Response processTotpUpdate(final MultivaluedMap<String, String> formData) {
|
||||||
AuthenticationManager.Auth auth = getAuth(true);
|
AuthenticationManager.Auth auth = getAuth(true);
|
||||||
|
if (!hasAccess(auth)) {
|
||||||
|
return noAccess();
|
||||||
|
}
|
||||||
|
|
||||||
UserModel user = auth.getUser();
|
UserModel user = auth.getUser();
|
||||||
|
|
||||||
String totp = formData.getFirst("totp");
|
String totp = formData.getFirst("totp");
|
||||||
|
@ -205,6 +222,10 @@ public class AccountService {
|
||||||
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
|
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
|
||||||
public Response processPasswordUpdate(final MultivaluedMap<String, String> formData) {
|
public Response processPasswordUpdate(final MultivaluedMap<String, String> formData) {
|
||||||
AuthenticationManager.Auth auth = getAuth(true);
|
AuthenticationManager.Auth auth = getAuth(true);
|
||||||
|
if (!hasAccess(auth)) {
|
||||||
|
return noAccess();
|
||||||
|
}
|
||||||
|
|
||||||
UserModel user = auth.getUser();
|
UserModel user = auth.getUser();
|
||||||
|
|
||||||
FormFlows forms = Flows.forms(realm, request, uriInfo).setUser(user);
|
FormFlows forms = Flows.forms(realm, request, uriInfo).setUser(user);
|
||||||
|
@ -336,30 +357,30 @@ public class AccountService {
|
||||||
return oauth.redirect(uriInfo, accountUri.toString(), path);
|
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);
|
AuthenticationManager.Auth auth = authManager.authenticateAccountIdentity(realm, uriInfo, headers);
|
||||||
if (auth == null && required) {
|
if (auth == null && error) {
|
||||||
throw new ForbiddenException();
|
throw new ForbiddenException();
|
||||||
}
|
}
|
||||||
return auth;
|
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();
|
UserModel client = auth.getClient();
|
||||||
|
|
||||||
if (realm.hasRole(client, Constants.APPLICATION_ROLE)) {
|
if (realm.hasRole(client, Constants.APPLICATION_ROLE)) {
|
||||||
return true;
|
// Tokens from cookies don't have roles
|
||||||
}
|
if (hasRole(client, Constants.ACCOUNT_MANAGE_ROLE) || (role != null && hasRole(client, role))) {
|
||||||
|
|
||||||
SkeletonKeyToken token = auth.getToken();
|
|
||||||
SkeletonKeyToken.Access access = token.getResourceAccess(application.getName());
|
|
||||||
|
|
||||||
if (access != null) {
|
|
||||||
if (access.isUserInRole(Constants.ACCOUNT_MANAGE_ROLE)) {
|
|
||||||
return true;
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -367,4 +388,11 @@ public class AccountService {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean hasRole(UserModel user, String role) {
|
||||||
|
if (application.getDefaultRoles().contains(role)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return application.hasRole(user, role);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -176,10 +176,6 @@ public class SocialResource {
|
||||||
}
|
}
|
||||||
|
|
||||||
realm.addSocialLink(user, socialLink);
|
realm.addSocialLink(user, socialLink);
|
||||||
|
|
||||||
for (RoleModel role : realm.getDefaultRoles()) {
|
|
||||||
realm.grantRole(user, role);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// Redirect user to registration screen with prefilled data from social provider
|
// Redirect user to registration screen with prefilled data from social provider
|
||||||
MultivaluedMap<String, String> formData = fillRegistrationFormWithSocialData(socialUser);
|
MultivaluedMap<String, String> formData = fillRegistrationFormWithSocialData(socialUser);
|
||||||
|
|
|
@ -309,10 +309,6 @@ public class TokenService {
|
||||||
realm.updateCredential(user, credentials);
|
realm.updateCredential(user, credentials);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (RoleModel role : realm.getDefaultRoles()) {
|
|
||||||
realm.grantRole(user, role);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -73,7 +73,7 @@ public class AdapterTest extends AbstractKeycloakTest {
|
||||||
Assert.assertEquals(realmModel.getPublicKeyPem(), "0234234");
|
Assert.assertEquals(realmModel.getPublicKeyPem(), "0234234");
|
||||||
Assert.assertEquals(realmModel.isAutomaticRegistrationAfterSocialLogin(), true);
|
Assert.assertEquals(realmModel.isAutomaticRegistrationAfterSocialLogin(), true);
|
||||||
Assert.assertEquals(1, realmModel.getDefaultRoles().size());
|
Assert.assertEquals(1, realmModel.getDefaultRoles().size());
|
||||||
Assert.assertEquals("foo", realmModel.getDefaultRoles().get(0).getName());
|
Assert.assertEquals("foo", realmModel.getDefaultRoles().get(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -102,7 +102,7 @@ public class AdapterTest extends AbstractKeycloakTest {
|
||||||
Assert.assertEquals(realmModel.getPublicKeyPem(), "0234234");
|
Assert.assertEquals(realmModel.getPublicKeyPem(), "0234234");
|
||||||
Assert.assertEquals(realmModel.isAutomaticRegistrationAfterSocialLogin(), true);
|
Assert.assertEquals(realmModel.isAutomaticRegistrationAfterSocialLogin(), true);
|
||||||
Assert.assertEquals(1, realmModel.getDefaultRoles().size());
|
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();
|
String id = realmModel.getId();
|
||||||
System.out.println("id: " + id);
|
System.out.println("id: " + id);
|
||||||
|
|
|
@ -42,6 +42,8 @@ public class ApplicationModelTest extends AbstractKeycloakServerTest {
|
||||||
application.setName("app-name");
|
application.setName("app-name");
|
||||||
application.addRole("role-1");
|
application.addRole("role-1");
|
||||||
application.addRole("role-2");
|
application.addRole("role-2");
|
||||||
|
application.addDefaultRole("role-1");
|
||||||
|
application.addDefaultRole("role-2");
|
||||||
|
|
||||||
application.getApplicationUser().addRedirectUri("redirect-1");
|
application.getApplicationUser().addRedirectUri("redirect-1");
|
||||||
application.getApplicationUser().addRedirectUri("redirect-2");
|
application.getApplicationUser().addRedirectUri("redirect-2");
|
||||||
|
@ -80,6 +82,7 @@ public class ApplicationModelTest extends AbstractKeycloakServerTest {
|
||||||
Assert.assertEquals(expected.getName(), actual.getName());
|
Assert.assertEquals(expected.getName(), actual.getName());
|
||||||
Assert.assertEquals(expected.getBaseUrl(), actual.getBaseUrl());
|
Assert.assertEquals(expected.getBaseUrl(), actual.getBaseUrl());
|
||||||
Assert.assertEquals(expected.getManagementUrl(), actual.getManagementUrl());
|
Assert.assertEquals(expected.getManagementUrl(), actual.getManagementUrl());
|
||||||
|
Assert.assertEquals(expected.getDefaultRoles(), actual.getDefaultRoles());
|
||||||
|
|
||||||
UserModel auser = actual.getApplicationUser();
|
UserModel auser = actual.getApplicationUser();
|
||||||
UserModel euser = expected.getApplicationUser();
|
UserModel euser = expected.getApplicationUser();
|
||||||
|
|
|
@ -86,7 +86,7 @@ public class ModelTest extends AbstractKeycloakServerTest {
|
||||||
Assert.assertEquals(expected.getPublicKeyPem(), actual.getPublicKeyPem());
|
Assert.assertEquals(expected.getPublicKeyPem(), actual.getPublicKeyPem());
|
||||||
Assert.assertEquals(expected.getPrivateKeyPem(), actual.getPrivateKeyPem());
|
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.getSmtpConfig(), actual.getSmtpConfig());
|
||||||
Assert.assertEquals(expected.getSocialConfig(), actual.getSocialConfig());
|
Assert.assertEquals(expected.getSocialConfig(), actual.getSocialConfig());
|
||||||
|
|
|
@ -29,6 +29,8 @@ import javax.ws.rs.core.MediaType;
|
||||||
import javax.ws.rs.core.UriBuilder;
|
import javax.ws.rs.core.UriBuilder;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
|
@ -51,17 +53,13 @@ public class ProfileTest {
|
||||||
|
|
||||||
ApplicationModel accountApp = appRealm.getApplicationNameMap().get(org.keycloak.models.Constants.ACCOUNT_APPLICATION);
|
ApplicationModel accountApp = appRealm.getApplicationNameMap().get(org.keycloak.models.Constants.ACCOUNT_APPLICATION);
|
||||||
|
|
||||||
accountApp.grantRole(user, accountApp.getRole(org.keycloak.models.Constants.ACCOUNT_PROFILE_ROLE));
|
ApplicationModel app = appRealm.getApplicationNameMap().get("test-app");
|
||||||
accountApp.grantRole(user, accountApp.getRole(org.keycloak.models.Constants.ACCOUNT_MANAGE_ROLE));
|
accountApp.addScopeMapping(app.getApplicationUser(), org.keycloak.models.Constants.ACCOUNT_PROFILE_ROLE);
|
||||||
|
|
||||||
|
app.getApplicationUser().addWebOrigin("http://localtest.me:8081");
|
||||||
|
|
||||||
UserModel thirdParty = appRealm.getUser("third-party");
|
UserModel thirdParty = appRealm.getUser("third-party");
|
||||||
accountApp.addScopeMapping(thirdParty, org.keycloak.models.Constants.ACCOUNT_PROFILE_ROLE);
|
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
|
@WebResource
|
||||||
protected OAuthGrantPage grantPage;
|
protected OAuthGrantPage grantPage;
|
||||||
|
|
||||||
|
private List<String> defaultRoles;
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getProfile() throws Exception {
|
public void getProfile() throws Exception {
|
||||||
oauth.doLogin("test-user@localhost", "password");
|
oauth.doLogin("test-user@localhost", "password");
|
||||||
|
@ -119,7 +119,7 @@ public class ProfileTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getProfileCorsInvalidOrigin() throws Exception {
|
public void getProfileCorsInvalidOrigin() throws Exception {
|
||||||
oauth.doLogin("test-user@localhost", "password");
|
oauth.doLogin("test-user@localhost", "password");
|
||||||
|
|
||||||
String code = oauth.getCurrentQuery().get("code");
|
String code = oauth.getCurrentQuery().get("code");
|
||||||
|
@ -152,6 +152,35 @@ public class ProfileTest {
|
||||||
assertEquals(403, response.getStatusLine().getStatusCode());
|
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
|
@Test
|
||||||
public void getProfileOAuthClient() throws Exception {
|
public void getProfileOAuthClient() throws Exception {
|
||||||
oauth.addScope(org.keycloak.models.Constants.ACCOUNT_APPLICATION, org.keycloak.models.Constants.ACCOUNT_PROFILE_ROLE);
|
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("req.send(null);\n");
|
||||||
sb.append("return req.status + '///' + req.responseText;\n");
|
sb.append("return req.status + '///' + req.responseText;\n");
|
||||||
|
|
||||||
JavascriptExecutor js = (JavascriptExecutor) driver;
|
JavascriptExecutor js = (JavascriptExecutor) driver;
|
||||||
String response = (String) js.executeScript(sb.toString());
|
String response = (String) js.executeScript(sb.toString());
|
||||||
return response.split("///");
|
return response.split("///");
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,19 +21,14 @@
|
||||||
*/
|
*/
|
||||||
package org.keycloak.testsuite.forms;
|
package org.keycloak.testsuite.forms;
|
||||||
|
|
||||||
|
import org.apache.http.HttpResponse;
|
||||||
import org.junit.*;
|
import org.junit.*;
|
||||||
|
import org.keycloak.models.*;
|
||||||
import org.keycloak.representations.idm.CredentialRepresentation;
|
import org.keycloak.representations.idm.CredentialRepresentation;
|
||||||
import org.keycloak.services.managers.RealmManager;
|
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.OAuthClient;
|
||||||
import org.keycloak.testsuite.pages.AccountPasswordPage;
|
import org.keycloak.testsuite.pages.*;
|
||||||
import org.keycloak.testsuite.pages.AccountTotpPage;
|
|
||||||
import org.keycloak.testsuite.pages.AccountUpdateProfilePage;
|
|
||||||
import org.keycloak.testsuite.pages.AppPage;
|
|
||||||
import org.keycloak.testsuite.pages.AppPage.RequestType;
|
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;
|
||||||
import org.keycloak.testsuite.rule.KeycloakRule.KeycloakSetup;
|
import org.keycloak.testsuite.rule.KeycloakRule.KeycloakSetup;
|
||||||
import org.keycloak.testsuite.rule.WebResource;
|
import org.keycloak.testsuite.rule.WebResource;
|
||||||
|
@ -43,6 +38,10 @@ import org.openqa.selenium.WebElement;
|
||||||
import org.openqa.selenium.support.FindBy;
|
import org.openqa.selenium.support.FindBy;
|
||||||
import org.picketlink.idm.credential.util.TimeBasedOTP;
|
import org.picketlink.idm.credential.util.TimeBasedOTP;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||||
*/
|
*/
|
||||||
|
@ -75,8 +74,13 @@ public class AccountTest {
|
||||||
@WebResource
|
@WebResource
|
||||||
protected AccountTotpPage totpPage;
|
protected AccountTotpPage totpPage;
|
||||||
|
|
||||||
|
@WebResource
|
||||||
|
protected ErrorPage errorPage;
|
||||||
|
|
||||||
private TimeBasedOTP totp = new TimeBasedOTP();
|
private TimeBasedOTP totp = new TimeBasedOTP();
|
||||||
|
|
||||||
|
private List<String> defaultRoles;
|
||||||
|
|
||||||
@After
|
@After
|
||||||
public void after() {
|
public void after() {
|
||||||
keycloakRule.configure(new KeycloakSetup() {
|
keycloakRule.configure(new KeycloakSetup() {
|
||||||
|
@ -183,4 +187,31 @@ public class AccountTest {
|
||||||
Assert.assertTrue(driver.getPageSource().contains("Remove Google"));
|
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());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -78,13 +78,6 @@ public class CreateUsersWorker implements Worker {
|
||||||
user.setEmail(username + "@email.com");
|
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)
|
// Creating password (will be same as username)
|
||||||
if (addPassword) {
|
if (addPassword) {
|
||||||
UserCredentialModel password = new UserCredentialModel();
|
UserCredentialModel password = new UserCredentialModel();
|
||||||
|
|
Loading…
Reference in a new issue