use of org.keycloak.models.CibaConfig in project keycloak by keycloak.
the class BackchannelAuthenticationCallbackEndpoint method processAuthenticationChannelResult.
@Path("/")
@POST
@NoCache
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public Response processAuthenticationChannelResult(AuthenticationChannelResponse response) {
event.event(EventType.LOGIN);
BackchannelAuthCallbackContext ctx = verifyAuthenticationRequest(httpRequest.getHttpHeaders());
AccessToken bearerToken = ctx.bearerToken;
OAuth2DeviceCodeModel deviceModel = ctx.deviceModel;
Status status = response.getStatus();
if (status == null) {
event.error(Errors.INVALID_REQUEST);
throw new ErrorResponseException(OAuthErrorException.INVALID_REQUEST, "Invalid authentication status", Response.Status.BAD_REQUEST);
}
switch(status) {
case SUCCEED:
approveRequest(bearerToken, response.getAdditionalParams());
break;
case CANCELLED:
case UNAUTHORIZED:
denyRequest(bearerToken, status);
break;
}
// Call the notification endpoint
ClientModel client = session.getContext().getClient();
CibaConfig cibaConfig = realm.getCibaPolicy();
if (cibaConfig.getBackchannelTokenDeliveryMode(client).equals(CibaConfig.CIBA_PING_MODE)) {
sendClientNotificationRequest(client, cibaConfig, deviceModel);
}
return Response.ok(MediaType.APPLICATION_JSON_TYPE).build();
}
use of org.keycloak.models.CibaConfig in project keycloak by keycloak.
the class CibaClientValidation method validate.
public void validate() {
ClientModel client = context.getObjectToValidate();
// Check only ping mode and poll mode allowed
CibaConfig cibaConfig = client.getRealm().getCibaPolicy();
String cibaMode = cibaConfig.getBackchannelTokenDeliveryMode(client);
if (!CibaConfig.CIBA_SUPPORTED_MODES.contains(cibaMode)) {
context.addError("cibaBackchannelTokenDeliveryMode", "Unsupported requested CIBA Backchannel Token Delivery Mode", "invalidCibaBackchannelTokenDeliveryMode");
}
// Check clientNotificationEndpoint URL configured for ping mode
if (CibaConfig.CIBA_PING_MODE.equals(cibaMode)) {
if (cibaConfig.getBackchannelClientNotificationEndpoint(client) == null) {
context.addError("cibaBackchannelClientNotificationEndpoint", "CIBA Backchannel Client Notification Endpoint must be set for the CIBA ping mode", "missingCibaBackchannelClientNotificationEndpoint");
}
}
// Validate clientNotificationEndpoint URL itself
try {
checkUrl(client.getRealm().getSslRequired(), cibaConfig.getBackchannelClientNotificationEndpoint(client), "backchannel_client_notification_endpoint");
} catch (RuntimeException re) {
context.addError("cibaBackchannelClientNotificationEndpoint", re.getMessage(), "invalidBackchannelClientNotificationEndpoint");
}
Algorithm alg = cibaConfig.getBackchannelAuthRequestSigningAlg(client);
if (alg != null && !isSupportedBackchannelAuthenticationRequestSigningAlg(context.getSession(), alg.name())) {
context.addError("cibaBackchannelAuthRequestSigningAlg", "Unsupported requested CIBA Backchannel Authentication Request Signing Algorithm", "invalidCibaBackchannelAuthRequestSigningAlg");
}
}
use of org.keycloak.models.CibaConfig in project keycloak by keycloak.
the class BackchannelAuthenticationEndpoint method authorizeClient.
private CIBAAuthenticationRequest authorizeClient(MultivaluedMap<String, String> params) {
ClientModel client = null;
try {
client = authenticateClient();
} catch (WebApplicationException wae) {
OAuth2ErrorRepresentation errorRep = (OAuth2ErrorRepresentation) wae.getResponse().getEntity();
throw new ErrorResponseException(errorRep.getError(), errorRep.getErrorDescription(), Response.Status.UNAUTHORIZED);
}
BackchannelAuthenticationEndpointRequest endpointRequest = BackchannelAuthenticationEndpointRequestParserProcessor.parseRequest(event, session, client, params, realm.getCibaPolicy());
UserModel user = resolveUser(endpointRequest, realm.getCibaPolicy().getAuthRequestedUserHint());
CIBAAuthenticationRequest request = new CIBAAuthenticationRequest(session, user, client);
request.setClient(client);
String scope = endpointRequest.getScope();
if (scope == null) {
throw new ErrorResponseException(OAuthErrorException.INVALID_REQUEST, "missing parameter : scope", Response.Status.BAD_REQUEST);
}
request.setScope(scope);
// optional parameters
if (endpointRequest.getBindingMessage() != null) {
validateBindingMessage(endpointRequest.getBindingMessage());
request.setBindingMessage(endpointRequest.getBindingMessage());
}
if (endpointRequest.getAcr() != null)
request.setAcrValues(endpointRequest.getAcr());
CibaConfig policy = realm.getCibaPolicy();
// create JWE encoded auth_req_id from Auth Req ID.
Integer expiresIn = Optional.ofNullable(endpointRequest.getRequestedExpiry()).orElse(policy.getExpiresIn());
request.exp(request.getIat() + expiresIn.longValue());
StringBuilder scopes = new StringBuilder(Optional.ofNullable(request.getScope()).orElse(""));
client.getClientScopes(true).forEach((key, value) -> {
if (value.isDisplayOnConsentScreen())
scopes.append(" ").append(value.getName());
});
request.setScope(scopes.toString());
if (endpointRequest.getClientNotificationToken() != null) {
if (!policy.getBackchannelTokenDeliveryMode(client).equals(CibaConfig.CIBA_PING_MODE)) {
throw new ErrorResponseException(OAuthErrorException.INVALID_REQUEST, "Client Notification token supported only for the ping mode", Response.Status.BAD_REQUEST);
}
if (endpointRequest.getClientNotificationToken().length() > 1024) {
throw new ErrorResponseException(OAuthErrorException.INVALID_REQUEST, "Client Notification token length is limited to 1024 characters", Response.Status.BAD_REQUEST);
}
request.setClientNotificationToken(endpointRequest.getClientNotificationToken());
}
if (endpointRequest.getClientNotificationToken() == null && policy.getBackchannelTokenDeliveryMode(client).equals(CibaConfig.CIBA_PING_MODE)) {
throw new ErrorResponseException(OAuthErrorException.INVALID_REQUEST, "Client Notification token needs to be provided with the ping mode", Response.Status.BAD_REQUEST);
}
if (endpointRequest.getUserCode() != null) {
throw new ErrorResponseException(OAuthErrorException.INVALID_REQUEST, "User code not supported", Response.Status.BAD_REQUEST);
}
extractAdditionalParams(endpointRequest, request);
try {
session.clientPolicy().triggerOnEvent(new BackchannelAuthenticationRequestContext(endpointRequest, request, params));
} catch (ClientPolicyException cpe) {
throw new ErrorResponseException(cpe.getError(), cpe.getErrorDetail(), Response.Status.BAD_REQUEST);
}
return request;
}
use of org.keycloak.models.CibaConfig in project keycloak by keycloak.
the class BackchannelAuthenticationEndpoint method processGrantRequest.
@POST
@NoCache
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
@Produces(MediaType.APPLICATION_JSON)
public Response processGrantRequest(@Context HttpRequest httpRequest) {
CIBAAuthenticationRequest request = authorizeClient(httpRequest.getDecodedFormParameters());
try {
String authReqId = request.serialize(session);
AuthenticationChannelProvider provider = session.getProvider(AuthenticationChannelProvider.class);
if (provider == null) {
throw new RuntimeException("Authentication Channel Provider not found.");
}
CIBALoginUserResolver resolver = session.getProvider(CIBALoginUserResolver.class);
if (resolver == null) {
throw new RuntimeException("CIBA Login User Resolver not setup properly.");
}
UserModel user = request.getUser();
String infoUsedByAuthentication = resolver.getInfoUsedByAuthentication(user);
if (provider.requestAuthentication(request, infoUsedByAuthentication)) {
CibaConfig cibaPolicy = realm.getCibaPolicy();
int poolingInterval = cibaPolicy.getPoolingInterval();
storeAuthenticationRequest(request, cibaPolicy, authReqId);
ObjectNode response = JsonSerialization.createObjectNode();
response.put(CibaGrantType.AUTH_REQ_ID, authReqId).put(OAuth2Constants.EXPIRES_IN, cibaPolicy.getExpiresIn());
if (poolingInterval > 0) {
response.put(OAuth2Constants.INTERVAL, poolingInterval);
}
return Response.ok(JsonSerialization.writeValueAsBytes(response)).build();
}
} catch (Exception e) {
throw new ErrorResponseException(OAuthErrorException.SERVER_ERROR, "Failed to send authentication request", Response.Status.SERVICE_UNAVAILABLE);
}
throw new ErrorResponseException(OAuthErrorException.SERVER_ERROR, "Unexpected response from authentication device", Response.Status.SERVICE_UNAVAILABLE);
}
use of org.keycloak.models.CibaConfig in project keycloak by keycloak.
the class RepresentationToModel method updateCibaSettings.
private static void updateCibaSettings(RealmRepresentation rep, RealmModel realm) {
Map<String, String> newAttributes = rep.getAttributesOrEmpty();
CibaConfig cibaPolicy = realm.getCibaPolicy();
cibaPolicy.setBackchannelTokenDeliveryMode(newAttributes.get(CibaConfig.CIBA_BACKCHANNEL_TOKEN_DELIVERY_MODE));
cibaPolicy.setExpiresIn(newAttributes.get(CibaConfig.CIBA_EXPIRES_IN));
cibaPolicy.setPoolingInterval(newAttributes.get(CibaConfig.CIBA_INTERVAL));
cibaPolicy.setAuthRequestedUserHint(newAttributes.get(CibaConfig.CIBA_AUTH_REQUESTED_USER_HINT));
}
Aggregations