8000 move phishing check by edewit · Pull Request #48495 · keycloak/keycloak · GitHub
[go: up one dir, main page]

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ public class DefaultClientApi implements ClientApi {
private final KeycloakSession session;
private final String clientId;
private final RealmModel realm;
private final AdminPermissionEvaluator permissions;
private final ClientService clientService;

public DefaultClientApi(@Nonnull KeycloakSession session,
Expand All @@ -39,6 +40,7 @@ public DefaultClientApi(@Nonnull KeycloakSession session,
this.session = session;
this.clientId = clientId;
this.realm = realm;
this.permissions = permissions;
this.clientService = new DefaultClientService(session, realm, permissions, realmAdminResource);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import jakarta.annotation.Nonnull;
import jakarta.validation.Valid;
import jakarta.ws.rs.ForbiddenException;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
Expand Down Expand Up @@ -55,9 +56,20 @@ public Response createClient(@Valid BaseClientRepresentation client) {
.build();
}

/**
* When the path {@code clientId} does not resolve, return 403 if the caller cannot list clients
* (anti client-ID phishing), matching {@code ClientsResource#getClient} for Admin API v1.
*/
private void enforceAntiPhishingIfClientMissing(String clientId) {
if (realm.getClientByClientId(clientId) == null && !permissions.clients().canList()) {
throw new ForbiddenException();
}
}

@Path("{id}")
@Override
public ClientApi client(@PathParam("id") String clientId) {
enforceAntiPhishingIfClientMissing(clientId);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This enforces the check also for PUT which would mean PUT can't create without list permissions, right? That's not correct, AFAICT.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, it will get resolved later by #47804. It's not ideal but I agree we don't need to create workarounds for that, especially when v1 has the same issue.

LGTM then.

return new DefaultClientApi(session, realm, clientId, permissions, realmAdminResource);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,19 +95,14 @@ public DefaultClientService(@Nonnull KeycloakSession session,
this.rolesService = new RolesService(session, realm, permissions, adminEventBuilder);
}

protected Optional<ClientModel> avoidClientIdPhishing(ClientModel client) throws ServiceException {
if (client == null && !permissions.clients().canList()) {
// we do this to make sure somebody can't phish client IDs
throw new ServiceException(Response.Status.FORBIDDEN);
}
return Optional.ofNullable(client);
}

@Override
public Optional<BaseClientRepresentation> getClient(@Nonnull RealmModel realm,
@Nonnull String clientId,
ClientProjectionOptions projectionOptions) throws ServiceException {
ClientModel client = avoidClientIdPhishing(realm.getClientByClientId(clientId)).orElseThrow(() -> new ServiceException("Could not find client", Response.Status.NOT_FOUND));
ClientModel client = realm.getClientByClientId(clientId);
if (client == null) {
return Optional.empty();
}
permissions.clients().requireView(client);

try {
Expand Down Expand Up @@ -151,8 +146,10 @@ public CreateOrUpdateResult createOrUpdateClient(RealmModel realm, String client

@Override
public void deleteClient(RealmModel realm, String clientId) throws ServiceException {
ClientModel client = avoidClientIdPhishing(realm.getClientByClientId(clientId))
.orElseThrow(() -> new ServiceException("Could not find client", Response.Status.NOT_FOUND));
ClientModel client = realm.getClientByClientId(clientId);
if (client == null) {
throw new ServiceException("Could not find client", Response.Status.NOT_FOUND);
}

permissions.clients().requireManage(client);
try {
Expand Down Expand Up @@ -234,7 +231,7 @@ private CreateOrUpdateResult createOrUpdate(RealmModel realm, String clientId, B
ClientModel model = null;
if (!strategy.equals(CreateOrUpdateStrategy.ONLY_CREATE)) {
assertSameClientIds(clientId, client.getClientId());
model = avoidClientIdPhishing(realm.getClientByClientId(clientId)).orElse(null);
model = realm.getClientByClientId(clientId);
}
boolean alreadyExists = model != null;
ClientModelMapper mapper = getMapper(client.getProtocol());
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ void testGetNonExistentClient() {
CommandResult result = kcAdmV2Cmd("client", "get", "non-existent-id");

assertThat("get non-existent client should fail", result.exitCode(), is(not(0)));
assertThat(result.err(), containsString("Could not find client"));
assertThat(result.err(), containsString("Cannot find the specified client"));
}

@Test
Expand Down Expand Up @@ -470,7 +470,7 @@ void testGetClientWithSpecialCharsInId() {

assertThat("should fail for non-existent client", result.exitCode(), is(not(0)));
assertThat("URL-encoded ID should reach the server and get a proper 404, not a malformed URL error",
result.err(), containsString("Could not find client"));
result.err(), containsString("Cannot find the specified client"));
}

@Test
Expand Down Expand Up @@ -572,7 +572,7 @@ void testDeleteClient() throws Exception {

getResult = kcAdmV2Cmd("client", "get", id);
assertThat("get after delete should fail", getResult.exitCode(), is(not(0)));
assertThat(getResult.err(), containsString("Could not find client"));
assertThat(getResult.err(), containsString("Cannot find the specified client"));
}

@Test
Expand Down
Loading
0