Skip to content

Commit aba0b71

Browse files
authored
Enforce realm admin roles and permission when managing resources
Closes keycloak#47072 Signed-off-by: Pedro Igor <pigor.craveiro@gmail.com>
1 parent d11136f commit aba0b71

11 files changed

Lines changed: 467 additions & 100 deletions

File tree

scim/core/src/main/java/org/keycloak/scim/resource/spi/AbstractScimResourceTypeProvider.java

Lines changed: 24 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
import java.util.stream.Stream;
77

88
import org.keycloak.authorization.fgap.AdminPermissionsSchema;
9-
import org.keycloak.models.KeycloakContext;
109
import org.keycloak.models.KeycloakSession;
1110
import org.keycloak.models.Model;
1211
import org.keycloak.models.ModelValidationException;
@@ -42,9 +41,7 @@ public AbstractScimResourceTypeProvider(KeycloakSession session, ModelSchema<M,
4241

4342
@Override
4443
public R create(R resource) {
45-
KeycloakContext context = session.getContext();
46-
47-
if (!context.hasPermission(getRealmResourceType(), AdminPermissionsSchema.MANAGE)) {
44+
if (!hasPermission(getRealmResourceType(), AdminPermissionsSchema.MANAGE)) {
4845
throw new ForbiddenException();
4946
}
5047

@@ -55,9 +52,7 @@ public R create(R resource) {
5552
public R update(R resource) {
5653
M model = getModel(resource.getId());
5754

58-
KeycloakContext context = session.getContext();
59-
60-
if (!context.hasPermission(model, getRealmResourceType(), AdminPermissionsSchema.MANAGE)) {
55+
if (!hasPermission(model, getRealmResourceType(), AdminPermissionsSchema.MANAGE)) {
6156
throw new ForbiddenException();
6257
}
6358

@@ -74,14 +69,12 @@ public R get(String id) {
7469
return null;
7570
}
7671

77-
R resource = createResourceTypeInstance();
78-
79-
KeycloakContext context = session.getContext();
80-
81-
if (!context.hasPermission(model, getRealmResourceType(), AdminPermissionsSchema.VIEW)) {
72+
if (!hasPermission(model, getRealmResourceType(), AdminPermissionsSchema.VIEW)) {
8273
throw new ForbiddenException();
8374
}
8475

76+
R resource = createResourceTypeInstance();
77+
8578
for (ModelSchema<M, R> schema : schemas) {
8679
schema.populate(resource, model);
8780
}
@@ -91,6 +84,10 @@ public R get(String id) {
9184

9285
@Override
9386
public Stream<R> getAll(SearchRequest searchRequest) {
87+
if (!canQuery()) {
88+
throw new ForbiddenException();
89+
}
90+
9491
return getModels(searchRequest).map(m -> {
9592
try {
9693
return get(m.getId());
@@ -103,9 +100,8 @@ public Stream<R> getAll(SearchRequest searchRequest) {
103100
@Override
104101
public boolean delete(String id) {
105102
M model = getModel(id);
106-
KeycloakContext context = session.getContext();
107103

108-
if (!context.hasPermission(model, getRealmResourceType(), AdminPermissionsSchema.MANAGE)) {
104+
if (!hasPermission(model, getRealmResourceType(), AdminPermissionsSchema.MANAGE)) {
109105
throw new ForbiddenException();
110106
}
111107

@@ -117,9 +113,8 @@ public void patch(R existing, List<PatchOperation> operations) {
117113
Objects.requireNonNull(existing, "existing cannot be null");
118114
Objects.requireNonNull(operations, "operations cannot be null");
119115
M model = getModel(existing.getId());
120-
KeycloakContext context = session.getContext();
121116

122-
if (!context.hasPermission(model, getRealmResourceType(), AdminPermissionsSchema.MANAGE)) {
117+
if (!hasPermission(model, getRealmResourceType(), AdminPermissionsSchema.MANAGE)) {
123118
throw new ForbiddenException();
124119
}
125120

@@ -186,4 +181,17 @@ private R createResourceTypeInstance() {
186181
throw new RuntimeException("Could not create instance of resource type " + getResourceType(), e);
187182
}
188183
}
184+
185+
private boolean canQuery() {
186+
return session.getContext().getPermissions().hasPermission(getRealmResourceType(), AdminPermissionsSchema.QUERY);
187+
}
188+
189+
private boolean hasPermission(String realmResourceType, String scope) {
190+
return session.getContext().getPermissions().hasPermission(realmResourceType, scope);
191+
}
192+
193+
private boolean hasPermission(M model, String realmResourceType, String scope) {
194+
return session.getContext().getPermissions().hasPermission(model, realmResourceType, scope);
195+
}
196+
189197
}

scim/model/src/main/java/org/keycloak/scim/model/user/UserResourceTypeProvider.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,13 @@ public UserResourceTypeProvider(KeycloakSession session) {
5555
@Override
5656
public User onCreate(User resource) {
5757
UserProfileProvider provider = session.getProvider(UserProfileProvider.class);
58-
UserProfile profile = provider.create(UserProfileContext.SCIM, Map.of(UserModel.USERNAME, resource.getUserName()));
58+
String userName = resource.getUserName();
59+
60+
if (userName == null) {
61+
throw new ModelValidationException("username is required");
62+
}
63+
64+
UserProfile profile = provider.create(UserProfileContext.SCIM, Map.of(UserModel.USERNAME, userName));
5965
UserModel model = profile.create(false);
6066

6167
populate(model, resource);

scim/services/src/main/java/org/keycloak/scim/services/ScimResourceTypeResource.java

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,8 @@ public Response search(SearchRequest searchRequest) {
128128
.peek(this::setMetadata);
129129
} catch (ScimFilterException e) {
130130
return badRequest(e.getMessage(), "invalidFilter");
131+
} catch (ForbiddenException fe) {
132+
return Response.status(Status.FORBIDDEN).build();
131133
}
132134

133135
if (resourceTypeProvider instanceof SingletonResourceTypeProvider<R>) {
@@ -152,21 +154,25 @@ public Response search(SearchRequest searchRequest) {
152154
@DELETE
153155
@Produces(APPLICATION_SCIM_JSON)
154156
public Response delete(@PathParam("id") String id) {
155-
R resource = getResource(id);
157+
try {
158+
R resource = getResource(id);
156159

157-
if (resource == null) {
158-
return resourceNotFound(id);
159-
}
160+
if (resource == null) {
161+
return resourceNotFound(id);
162+
}
160163

161-
if (resourceTypeProvider.delete(id)) {
162-
adminEvent.operation(OperationType.DELETE)
163-
.resourcePath(session.getContext().getUri())
164-
.representation(resource)
165-
.success();
166-
return Response.noContent().build();
167-
}
164+
if (resourceTypeProvider.delete(id)) {
165+
adminEvent.operation(OperationType.DELETE)
166+
.resourcePath(session.getContext().getUri())
167+
.representation(resource)
168+
.success();
169+
return Response.noContent().build();
170+
}
168171

169-
return badRequest("Could not delete resource not found with id " + id);
172+
return badRequest("Could not delete resource not found with id " + id);
173+
} catch (ForbiddenException fe) {
174+
return Response.status(Status.FORBIDDEN).build();
175+
}
170176
}
171177

172178
@Path("{id}")

0 commit comments

Comments
 (0)