json device code flow error responses

closes #11438
This commit is contained in:
Konstantinos Georgilakis 2022-04-12 17:00:00 +03:00 committed by Marek Posolda
parent be1e31dc68
commit ccc0449314
3 changed files with 54 additions and 11 deletions

View file

@ -30,6 +30,7 @@ public interface Errors {
String CLIENT_DISABLED = "client_disabled";
String INVALID_CLIENT_CREDENTIALS = "invalid_client_credentials";
String INVALID_CLIENT = "invalid_client";
String UNAUTHORIZED_CLIENT ="unauthorized_client";
String CONSENT_DENIED = "consent_denied";
String RESOLVE_REQUIRED_ACTIONS = "resolve_required_actions";

View file

@ -364,8 +364,7 @@ public class DeviceEndpoint extends AuthorizationEndpointBase implements RealmRe
if (client == null) {
event.error(Errors.INVALID_REQUEST);
throw new ErrorPageException(session, null, Response.Status.BAD_REQUEST, Messages.MISSING_PARAMETER,
OIDCLoginProtocol.CLIENT_ID_PARAM);
throw new ErrorResponseException(Errors.INVALID_REQUEST, "Missing parameters:"+ OIDCLoginProtocol.CLIENT_ID_PARAM,Response.Status.BAD_REQUEST);
}
checkClient(client.getClientId());
@ -376,8 +375,7 @@ public class DeviceEndpoint extends AuthorizationEndpointBase implements RealmRe
private ClientModel checkClient(String clientId) {
if (clientId == null) {
event.error(Errors.INVALID_REQUEST);
throw new ErrorPageException(session, null, Response.Status.BAD_REQUEST,
Messages.MISSING_PARAMETER, OIDCLoginProtocol.CLIENT_ID_PARAM);
throw new ErrorResponseException(Errors.INVALID_REQUEST, "Missing parameters:"+ OIDCLoginProtocol.CLIENT_ID_PARAM, Response.Status.BAD_REQUEST);
}
event.client(clientId);
@ -385,24 +383,22 @@ public class DeviceEndpoint extends AuthorizationEndpointBase implements RealmRe
ClientModel client = realm.getClientByClientId(clientId);
if (client == null) {
event.error(Errors.CLIENT_NOT_FOUND);
throw new ErrorPageException(session, null, Response.Status.BAD_REQUEST,
Messages.CLIENT_NOT_FOUND);
throw new ErrorResponseException(Errors.INVALID_CLIENT, "Client not found.", Response.Status.BAD_REQUEST);
}
if (!client.isEnabled()) {
event.error(Errors.CLIENT_DISABLED);
throw new ErrorPageException(session, null, Response.Status.BAD_REQUEST, Messages.CLIENT_DISABLED);
throw new ErrorResponseException(Errors.INVALID_CLIENT, "Client disabled.", Response.Status.BAD_REQUEST);
}
if (!realm.getOAuth2DeviceConfig().isOAuth2DeviceAuthorizationGrantEnabled(client)) {
event.error(Errors.NOT_ALLOWED);
throw new ErrorPageException(session, null, Response.Status.BAD_REQUEST,
Messages.OAUTH2_DEVICE_AUTHORIZATION_GRANT_DISABLED);
throw new ErrorResponseException(Errors.UNAUTHORIZED_CLIENT, "Client is not allowed to initiate OAuth 2.0 Device Authorization Grant. The flow is disabled for the client.", Response.Status.BAD_REQUEST);
}
if (client.isBearerOnly()) {
event.error(Errors.NOT_ALLOWED);
throw new ErrorPageException(session, null, Response.Status.FORBIDDEN, Messages.BEARER_ONLY);
throw new ErrorResponseException(Errors.UNAUTHORIZED_CLIENT, "Bearer-only applications are not allowed to initiate browser login.", Response.Status.FORBIDDEN);
}
String protocol = client.getProtocol();
@ -413,7 +409,7 @@ public class DeviceEndpoint extends AuthorizationEndpointBase implements RealmRe
}
if (!protocol.equals(OIDCLoginProtocol.LOGIN_PROTOCOL)) {
event.error(Errors.INVALID_CLIENT);
throw new ErrorPageException(session, null, Response.Status.BAD_REQUEST, "Wrong client protocol.");
throw new ErrorResponseException(Errors.UNAUTHORIZED_CLIENT, "Wrong client protocol." , Response.Status.BAD_REQUEST);
}
session.getContext().setClient(client);

View file

@ -28,6 +28,7 @@ import org.junit.Test;
import org.keycloak.OAuth2Constants;
import org.keycloak.admin.client.resource.ClientResource;
import org.keycloak.admin.client.resource.RealmResource;
import org.keycloak.events.Errors;
import org.keycloak.models.ClientScopeModel;
import org.keycloak.models.OAuth2DeviceConfig;
import org.keycloak.models.utils.KeycloakModelUtils;
@ -851,6 +852,51 @@ public class OAuth2DeviceAuthorizationGrantTest extends AbstractKeycloakTest {
verificationPage.assertInvalidUserCodePage();
}
@Test
public void testNotFoundClient() throws Exception {
oauth.realm(REALM_NAME);
oauth.clientId("test-device-public2");
OAuthClient.DeviceAuthorizationResponse response = oauth.doDeviceAuthorizationRequest("test-device-public2", null);
Assert.assertEquals(400, response.getStatusCode());
Assert.assertEquals(Errors.INVALID_CLIENT, response.getError());
Assert.assertEquals("Invalid client credentials", response.getErrorDescription());
}
@Test
public void testClientWithErrors() throws Exception {
try {
ClientResource client = ApiUtil.findClientByClientId(adminClient.realm(REALM_NAME), DEVICE_APP_PUBLIC);
ClientRepresentation clientRepresentation = client.toRepresentation();
clientRepresentation.getAttributes().put(OAuth2DeviceConfig.OAUTH2_DEVICE_AUTHORIZATION_GRANT_ENABLED, "false");
client.update(clientRepresentation);
oauth.realm(REALM_NAME);
oauth.clientId(DEVICE_APP_PUBLIC);
//DeviceAuthorizationGrant not enabled
OAuthClient.DeviceAuthorizationResponse response = oauth.doDeviceAuthorizationRequest(DEVICE_APP_PUBLIC, null);
Assert.assertEquals(400, response.getStatusCode());
Assert.assertEquals(Errors.UNAUTHORIZED_CLIENT, response.getError());
Assert.assertEquals("Client is not allowed to initiate OAuth 2.0 Device Authorization Grant. The flow is disabled for the client.", response.getErrorDescription());
clientRepresentation.getAttributes().put(OAuth2DeviceConfig.OAUTH2_DEVICE_AUTHORIZATION_GRANT_ENABLED, "true");
clientRepresentation.setBearerOnly(true);
client.update(clientRepresentation);
//BearerOnly client
response = oauth.doDeviceAuthorizationRequest(DEVICE_APP_PUBLIC, null);
Assert.assertEquals(403, response.getStatusCode());
Assert.assertEquals(Errors.UNAUTHORIZED_CLIENT, response.getError());
Assert.assertEquals("Bearer-only applications are not allowed to initiate browser login.", response.getErrorDescription());
} finally {
ClientResource client = ApiUtil.findClientByClientId(adminClient.realm(REALM_NAME), DEVICE_APP_PUBLIC);
ClientRepresentation clientRepresentation = client.toRepresentation();
clientRepresentation.getAttributes().put(OAuth2DeviceConfig.OAUTH2_DEVICE_AUTHORIZATION_GRANT_ENABLED, "true");
clientRepresentation.setBearerOnly(false);
client.update(clientRepresentation);
}
}
private void openVerificationPage(String verificationUri) {
driver.navigate().to(verificationUri);
}