/* * Copyright 2016 Red Hat, Inc. and/or its affiliates * and other contributors as indicated by the @author tags. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.keycloak.services.resources.admin; import org.jboss.resteasy.annotations.cache.NoCache; import org.jboss.resteasy.spi.NotFoundException; import org.keycloak.events.admin.OperationType; import org.keycloak.events.admin.ResourceType; import org.keycloak.models.ClientModel; import org.keycloak.models.ModelDuplicateException; import org.keycloak.models.RealmModel; import org.keycloak.models.RoleContainerModel; import org.keycloak.models.RoleModel; import org.keycloak.models.utils.ModelToRepresentation; import org.keycloak.representations.idm.RoleRepresentation; import org.keycloak.services.ErrorResponse; import javax.ws.rs.BadRequestException; import javax.ws.rs.Consumes; import javax.ws.rs.DELETE; import javax.ws.rs.GET; import javax.ws.rs.POST; import javax.ws.rs.PUT; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.ws.rs.core.UriInfo; import java.util.ArrayList; import java.util.List; import java.util.Set; /** * @resource Roles * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @version $Revision: 1 $ */ public class RoleContainerResource extends RoleResource { private final RealmModel realm; private final RealmAuth auth; protected RoleContainerModel roleContainer; private AdminEventBuilder adminEvent; private UriInfo uriInfo; public RoleContainerResource(UriInfo uriInfo, RealmModel realm, RealmAuth auth, RoleContainerModel roleContainer, AdminEventBuilder adminEvent) { super(realm); this.uriInfo = uriInfo; this.realm = realm; this.auth = auth; this.roleContainer = roleContainer; this.adminEvent = adminEvent; } /** * Get all roles for the realm or client * * @return */ @GET @NoCache @Produces(MediaType.APPLICATION_JSON) public List<RoleRepresentation> getRoles() { auth.requireAny(); if (roleContainer == null) { throw new NotFoundException("Could not find client"); } Set<RoleModel> roleModels = roleContainer.getRoles(); List<RoleRepresentation> roles = new ArrayList<RoleRepresentation>(); for (RoleModel roleModel : roleModels) { roles.add(ModelToRepresentation.toRepresentation(roleModel)); } return roles; } /** * Create a new role for the realm or client * * @param rep * @return */ @POST @Consumes(MediaType.APPLICATION_JSON) public Response createRole(final RoleRepresentation rep) { auth.requireManage(); if (roleContainer == null) { throw new NotFoundException("Could not find client"); } if (rep.getName() == null) { throw new BadRequestException(); } try { RoleModel role = roleContainer.addRole(rep.getName()); role.setDescription(rep.getDescription()); boolean scopeParamRequired = rep.isScopeParamRequired()==null ? false : rep.isScopeParamRequired(); role.setScopeParamRequired(scopeParamRequired); rep.setId(role.getId()); if (role.isClientRole()) { adminEvent.resource(ResourceType.CLIENT_ROLE); } else { adminEvent.resource(ResourceType.REALM_ROLE); } adminEvent.operation(OperationType.CREATE).resourcePath(uriInfo, role.getName()).representation(rep).success(); return Response.created(uriInfo.getAbsolutePathBuilder().path(role.getName()).build()).build(); } catch (ModelDuplicateException e) { return ErrorResponse.exists("Role with name " + rep.getName() + " already exists"); } } /** * Get a role by name * * @param roleName role's name (not id!) * @return */ @Path("{role-name}") @GET @NoCache @Produces(MediaType.APPLICATION_JSON) public RoleRepresentation getRole(final @PathParam("role-name") String roleName) { auth.requireView(); if (roleContainer == null) { throw new NotFoundException("Could not find client"); } RoleModel roleModel = roleContainer.getRole(roleName); if (roleModel == null) { throw new NotFoundException("Could not find role"); } return getRole(roleModel); } /** * Delete a role by name * * @param roleName role's name (not id!) */ @Path("{role-name}") @DELETE @NoCache public void deleteRole(final @PathParam("role-name") String roleName) { auth.requireManage(); if (roleContainer == null) { throw new NotFoundException("Could not find client"); } RoleModel role = roleContainer.getRole(roleName); if (role == null) { throw new NotFoundException("Could not find role"); } deleteRole(role); if (role.isClientRole()) { adminEvent.resource(ResourceType.CLIENT_ROLE); } else { adminEvent.resource(ResourceType.REALM_ROLE); } adminEvent.operation(OperationType.DELETE).resourcePath(uriInfo).success(); } /** * Update a role by name * * @param roleName role's name (not id!) * @param rep * @return */ @Path("{role-name}") @PUT @Consumes(MediaType.APPLICATION_JSON) public Response updateRole(final @PathParam("role-name") String roleName, final RoleRepresentation rep) { auth.requireManage(); if (roleContainer == null) { throw new NotFoundException("Could not find client"); } RoleModel role = roleContainer.getRole(roleName); if (role == null) { throw new NotFoundException("Could not find role"); } try { updateRole(rep, role); if (role.isClientRole()) { adminEvent.resource(ResourceType.CLIENT_ROLE); } else { adminEvent.resource(ResourceType.REALM_ROLE); } adminEvent.operation(OperationType.UPDATE).resourcePath(uriInfo).representation(rep).success(); return Response.noContent().build(); } catch (ModelDuplicateException e) { return ErrorResponse.exists("Role with name " + rep.getName() + " already exists"); } } /** * Add a composite to the role * * @param roleName role's name (not id!) * @param roles */ @Path("{role-name}/composites") @POST @Consumes(MediaType.APPLICATION_JSON) public void addComposites(final @PathParam("role-name") String roleName, List<RoleRepresentation> roles) { auth.requireManage(); if (roleContainer == null) { throw new NotFoundException("Could not find client"); } RoleModel role = roleContainer.getRole(roleName); if (role == null) { throw new NotFoundException("Could not find role"); } addComposites(adminEvent, uriInfo, roles, role); } /** * Get composites of the role * * @param roleName role's name (not id!) * @return */ @Path("{role-name}/composites") @GET @NoCache @Produces(MediaType.APPLICATION_JSON) public Set<RoleRepresentation> getRoleComposites(final @PathParam("role-name") String roleName) { auth.requireView(); if (roleContainer == null) { throw new NotFoundException("Could not find client"); } RoleModel role = roleContainer.getRole(roleName); if (role == null) { throw new NotFoundException("Could not find role"); } return getRoleComposites(role); } /** * Get realm-level roles of the role's composite * * @param roleName role's name (not id!) * @return */ @Path("{role-name}/composites/realm") @GET @NoCache @Produces(MediaType.APPLICATION_JSON) public Set<RoleRepresentation> getRealmRoleComposites(final @PathParam("role-name") String roleName) { auth.requireView(); if (roleContainer == null) { throw new NotFoundException("Could not find client"); } RoleModel role = roleContainer.getRole(roleName); if (role == null) { throw new NotFoundException("Could not find role"); } return getRealmRoleComposites(role); } /** * An app-level roles for the specified app for the role's composite * * @param roleName role's name (not id!) * @param client * @return */ @Path("{role-name}/composites/clients/{client}") @GET @NoCache @Produces(MediaType.APPLICATION_JSON) public Set<RoleRepresentation> getClientRoleComposites(@Context final UriInfo uriInfo, final @PathParam("role-name") String roleName, final @PathParam("client") String client) { auth.requireView(); if (roleContainer == null) { throw new NotFoundException("Could not find client"); } RoleModel role = roleContainer.getRole(roleName); if (role == null) { throw new NotFoundException("Could not find role"); } ClientModel clientModel = realm.getClientById(client); if (client == null) { throw new NotFoundException("Could not find client"); } return getClientRoleComposites(clientModel, role); } /** * Remove roles from the role's composite * * @param roleName role's name (not id!) * @param roles roles to remove */ @Path("{role-name}/composites") @DELETE @Consumes(MediaType.APPLICATION_JSON) public void deleteComposites( final @PathParam("role-name") String roleName, List<RoleRepresentation> roles) { auth.requireManage(); if (roleContainer == null) { throw new NotFoundException("Could not find client"); } RoleModel role = roleContainer.getRole(roleName); if (role == null) { throw new NotFoundException("Could not find role"); } deleteComposites(adminEvent, uriInfo, roles, role); } }