parent
b2e55762f1
commit
8f221bb21e
3 changed files with 57 additions and 1 deletions
|
@ -53,6 +53,9 @@ public class OAuthErrorException extends Exception {
|
|||
public static final String SLOW_DOWN = "slow_down";
|
||||
public static final String EXPIRED_TOKEN = "expired_token";
|
||||
|
||||
// CIBA
|
||||
public static final String INVALID_BINDING_MESSAGE = "invalid_binding_message";
|
||||
|
||||
// Others
|
||||
public static final String INVALID_CLIENT = "invalid_client";
|
||||
public static final String INVALID_GRANT = "invalid_grant";
|
||||
|
|
|
@ -54,6 +54,7 @@ import javax.ws.rs.core.Response;
|
|||
|
||||
import java.util.Collections;
|
||||
import java.util.Optional;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static org.keycloak.protocol.oidc.OIDCLoginProtocol.ID_TOKEN_HINT;
|
||||
import static org.keycloak.protocol.oidc.OIDCLoginProtocol.LOGIN_HINT_PARAM;
|
||||
|
@ -62,6 +63,8 @@ public class BackchannelAuthenticationEndpoint extends AbstractCibaEndpoint {
|
|||
|
||||
private final RealmModel realm;
|
||||
|
||||
private static final Pattern BINDING_MESSAGE_VALIDATION = Pattern.compile("^[a-zA-Z0-9-._+/!?#]{1,50}$");
|
||||
|
||||
public BackchannelAuthenticationEndpoint(KeycloakSession session, EventBuilder event) {
|
||||
super(session, event);
|
||||
this.realm = session.getContext().getRealm();
|
||||
|
@ -172,7 +175,10 @@ public class BackchannelAuthenticationEndpoint extends AbstractCibaEndpoint {
|
|||
request.setScope(scope);
|
||||
|
||||
// optional parameters
|
||||
if (endpointRequest.getBindingMessage() != null) request.setBindingMessage(endpointRequest.getBindingMessage());
|
||||
if (endpointRequest.getBindingMessage() != null) {
|
||||
validateBindingMessage(endpointRequest.getBindingMessage());
|
||||
request.setBindingMessage(endpointRequest.getBindingMessage());
|
||||
}
|
||||
if (endpointRequest.getAcr() != null) request.setAcrValues(endpointRequest.getAcr());
|
||||
|
||||
CibaConfig policy = realm.getCibaPolicy();
|
||||
|
@ -228,6 +234,13 @@ public class BackchannelAuthenticationEndpoint extends AbstractCibaEndpoint {
|
|||
}
|
||||
}
|
||||
|
||||
protected void validateBindingMessage(String bindingMessage) {
|
||||
if (!BINDING_MESSAGE_VALIDATION.matcher(bindingMessage).matches()) {
|
||||
throw new ErrorResponseException(OAuthErrorException.INVALID_BINDING_MESSAGE, "the binding_message value has to be max 50 characters in length and must contain only basic plain-text characters without spaces",
|
||||
Response.Status.BAD_REQUEST);
|
||||
}
|
||||
}
|
||||
|
||||
private UserModel resolveUser(BackchannelAuthenticationEndpointRequest endpointRequest, String authRequestedUserHint) {
|
||||
CIBALoginUserResolver resolver = session.getProvider(CIBALoginUserResolver.class);
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@ import org.apache.http.client.methods.CloseableHttpResponse;
|
|||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
|
||||
import static org.hamcrest.Matchers.notNullValue;
|
||||
import static org.hamcrest.Matchers.nullValue;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
@ -397,6 +398,45 @@ public class CIBATest extends AbstractClientPoliciesTest {
|
|||
}
|
||||
}
|
||||
|
||||
// Corresponds to the test fapi-ciba-id1-ensure-authorization-request-with-potentially-bad-binding-message from the FAPI CIBA conformance testsuite
|
||||
@Test
|
||||
public void testBadBindingMessage() throws Exception {
|
||||
ClientResource clientResource = null;
|
||||
ClientRepresentation clientRep = null;
|
||||
try {
|
||||
final String username = "nutzername-schwarz";
|
||||
clientResource = ApiUtil.findClientByClientId(adminClient.realm(TEST_REALM_NAME), TEST_CLIENT_NAME);
|
||||
clientRep = clientResource.toRepresentation();
|
||||
prepareCIBASettings(clientResource, clientRep);
|
||||
|
||||
// Binding message with non plain-text characters
|
||||
String bindingMessage = "1234 \uD83D\uDC4D\uD83C\uDFFF 品川 Lor";
|
||||
AuthenticationRequestAcknowledgement response = oauth.doBackchannelAuthenticationRequest(TEST_CLIENT_NAME, TEST_CLIENT_PASSWORD, username, bindingMessage, null);
|
||||
assertThat(response.getStatusCode(), is(equalTo(400)));
|
||||
assertThat(response.getError(), is(OAuthErrorException.INVALID_BINDING_MESSAGE));
|
||||
|
||||
// Long binding message
|
||||
bindingMessage = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud.";
|
||||
response = oauth.doBackchannelAuthenticationRequest(TEST_CLIENT_NAME, TEST_CLIENT_PASSWORD, username, bindingMessage, null);
|
||||
assertThat(response.getStatusCode(), is(equalTo(400)));
|
||||
assertThat(response.getError(), is(OAuthErrorException.INVALID_BINDING_MESSAGE));
|
||||
|
||||
// Empty binding message
|
||||
bindingMessage = "";
|
||||
response = oauth.doBackchannelAuthenticationRequest(TEST_CLIENT_NAME, TEST_CLIENT_PASSWORD, username, bindingMessage, null);
|
||||
assertThat(response.getStatusCode(), is(equalTo(400)));
|
||||
assertThat(response.getError(), is(OAuthErrorException.INVALID_BINDING_MESSAGE));
|
||||
|
||||
// Valid binding message
|
||||
bindingMessage = "Lorem_ipsum";
|
||||
response = oauth.doBackchannelAuthenticationRequest(TEST_CLIENT_NAME, TEST_CLIENT_PASSWORD, username, bindingMessage, null);
|
||||
assertThat(response.getStatusCode(), is(equalTo(200)));
|
||||
assertThat(response.getError(), is(nullValue()));
|
||||
} finally {
|
||||
revertCIBASettings(clientResource, clientRep);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore("Should never happen because the AD does not send any information about the user but only the status of the authentication")
|
||||
public void testDifferentUserAuthenticated() throws Exception {
|
||||
|
|
Loading…
Reference in a new issue