Skip to content
Open
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
5 changes: 5 additions & 0 deletions js/libs/keycloak-admin-client/openapi.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@
"maxLength" : 255,
"description" : "ID uniquely identifying this client. Validation: must not be blank; size must be between 1 and 255"
},
"type" : {
"type" : "string",
"maxLength" : 255,
"description" : "Client type. Validation: size must be between 0 and 255; on update/on patch: type cannot be changed for an existing client"
},
"displayName" : {
"type" : "string",
"maxLength" : 255,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@
affectedFieldNames = {"protocol"},
message = "protocol cannot be changed for an existing client",
groups = {PutClient.class, PatchClient.class})
@ServerManagedFieldUnmodified(
affectedFieldNames = {"type"},
message = "type cannot be changed for an existing client",
groups = {PutClient.class, PatchClient.class})
@ValidRedirectUris
public class BaseClientRepresentation extends BaseRepresentation {
public static final String DISCRIMINATOR_FIELD = "protocol";
Expand All @@ -52,6 +56,10 @@ public class BaseClientRepresentation extends BaseRepresentation {
@JsonPropertyDescription("ID uniquely identifying this client")
protected String clientId;

@Size(max = 255)
@JsonPropertyDescription("Client type")
private String type;

@Size(max = 255)
@JsonPropertyDescription("Human readable name of the client")
private String displayName;
Expand Down Expand Up @@ -105,11 +113,21 @@ public void setClientId(String clientId) {
this.clientId = clientId;
}

public String getType() {
return type;
}

public void setType(String type) {
markFieldAsExplicitlySet("type");
this.type = type;
}
Comment thread
arnabnandy7 marked this conversation as resolved.

public String getDisplayName() {
return displayName;
}

public void setDisplayName(String displayName) {
markFieldAsExplicitlySet("displayName");
this.displayName = displayName;
}

Expand All @@ -118,6 +136,7 @@ public String getDescription() {
}

public void setDescription(String description) {
markFieldAsExplicitlySet("description");
this.description = description;
}

Expand All @@ -126,6 +145,7 @@ public Boolean getEnabled() {
}

public void setEnabled(Boolean enabled) {
markFieldAsExplicitlySet("enabled");
this.enabled = enabled;
}

Expand All @@ -134,6 +154,7 @@ public String getAppUrl() {
}

public void setAppUrl(String appUrl) {
markFieldAsExplicitlySet("appUrl");
this.appUrl = appUrl;
}

Expand All @@ -142,15 +163,16 @@ public Set<String> getRedirectUris() {
}

public void setRedirectUris(Set<String> redirectUris) {
this.redirectUris = redirectUris;
markFieldAsExplicitlySet("redirectUris");
this.redirectUris = redirectUris == null ? new LinkedHashSet<>() : new LinkedHashSet<>(redirectUris);
}

Comment thread
arnabnandy7 marked this conversation as resolved.
public Set<String> getRoles() {
return roles;
}

public void setRoles(Set<String> roles) {
this.roles = roles;
this.roles = roles == null ? new LinkedHashSet<>() : new LinkedHashSet<>(roles);
}

public String getProtocol() {
Expand Down Expand Up @@ -183,19 +205,20 @@ public boolean equals(Object o) {
return false;
}
BaseClientRepresentation that = (BaseClientRepresentation)o;
return Objects.equals(uuid, that.uuid) && Objects.equals(clientId, that.clientId) && Objects.equals(displayName, that.displayName) && Objects.equals(description, that.description) && Objects.equals(enabled, that.enabled) && Objects.equals(appUrl, that.appUrl) && Objects.equals(redirectUris, that.redirectUris) && Objects.equals(roles, that.roles) && Objects.equals(protocol, that.protocol);
return Objects.equals(uuid, that.uuid) && Objects.equals(clientId, that.clientId) && Objects.equals(type, that.type) && Objects.equals(displayName, that.displayName) && Objects.equals(description, that.description) && Objects.equals(enabled, that.enabled) && Objects.equals(appUrl, that.appUrl) && Objects.equals(redirectUris, that.redirectUris) && Objects.equals(roles, that.roles) && Objects.equals(protocol, that.protocol);
}

@Override
public int hashCode() {
return Objects.hash(uuid, clientId, displayName, description, enabled, appUrl, redirectUris, roles, protocol);
return Objects.hash(uuid, clientId, type, displayName, description, enabled, appUrl, redirectUris, roles, protocol);
}

@Override
public String toString() {
return getClass().getSimpleName() + "{" + "protocol=" + getProtocol()
+ ", uuid=" + uuid
+ ", clientId=" + clientId
+ ", type=" + type
+ ", displayName=" + displayName
+ ", description=" + description
+ ", enabled=" + enabled
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package org.keycloak.representations.admin.v2;

import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;

import com.fasterxml.jackson.annotation.JsonAnyGetter;
import com.fasterxml.jackson.annotation.JsonAnySetter;
Expand All @@ -15,6 +17,9 @@ public class BaseRepresentation {
@JsonIgnore
protected Map<String, Object> additionalFields = new LinkedHashMap<String, Object>();

@JsonIgnore
private final Set<String> explicitlySetFields = new LinkedHashSet<>();

@JsonAnyGetter
public Map<String, Object> getAdditionalFields() {
return additionalFields;
Expand All @@ -28,4 +33,17 @@ public void setAdditionalField(String name, Object value) {
public void setAdditionalFields(Map<String, Object> additionalFields) {
this.additionalFields = additionalFields;
}

protected void markFieldAsExplicitlySet(String fieldName) {
explicitlySetFields.add(fieldName);
}

@JsonIgnore
public boolean isFieldExplicitlySet(String fieldName) {
return explicitlySetFields.contains(fieldName);
}

public void clearExplicitlySetFields() {
explicitlySetFields.clear();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -71,14 +71,16 @@ public Set<Flow> getLoginFlows() {
}

public void setLoginFlows(Set<Flow> loginFlows) {
this.loginFlows = loginFlows;
markFieldAsExplicitlySet("loginFlows");
this.loginFlows = loginFlows == null ? new LinkedHashSet<>() : new LinkedHashSet<>(loginFlows);
}
Comment thread
arnabnandy7 marked this conversation as resolved.

public Auth getAuth() {
return auth;
}

public void setAuth(Auth auth) {
markFieldAsExplicitlySet("auth");
this.auth = auth;
}

Expand All @@ -87,15 +89,16 @@ public Set<String> getWebOrigins() {
}

public void setWebOrigins(Set<String> webOrigins) {
this.webOrigins = webOrigins;
markFieldAsExplicitlySet("webOrigins");
this.webOrigins = webOrigins == null ? new LinkedHashSet<>() : new LinkedHashSet<>(webOrigins);
}
Comment thread
arnabnandy7 marked this conversation as resolved.

public Set<String> getServiceAccountRoles() {
return serviceAccountRoles;
}

public void setServiceAccountRoles(Set<String> serviceAccountRoles) {
this.serviceAccountRoles = serviceAccountRoles;
this.serviceAccountRoles = serviceAccountRoles == null ? new LinkedHashSet<>() : new LinkedHashSet<>(serviceAccountRoles);
}

@ClientSecretNotBlank(groups = PutClient.class, affectedFieldNames = {"secret"})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ public Boolean getFrontChannelLogout() {
}

public void setFrontChannelLogout(Boolean frontChannelLogout) {
markFieldAsExplicitlySet("frontChannelLogout");
this.frontChannelLogout = frontChannelLogout;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ public BaseClientModelMapper() {
this.addMapping("uuid", BaseClientRepresentation::getUuid, BaseClientRepresentation::setUuid, ClientModel::getId, null).readOnly = true;
this.addMapping("enabled", BaseClientRepresentation::getEnabled, BaseClientRepresentation::setEnabled, ClientModel::isEnabled, (model, enabled) -> model.setEnabled(Boolean.TRUE.equals(enabled)));
this.addMapping("clientId", BaseClientRepresentation::getClientId, BaseClientRepresentation::setClientId, ClientModel::getClientId, ClientModel::setClientId);
this.addMapping("type", BaseClientRepresentation::getType, BaseClientRepresentation::setType, ClientModel::getType, null);
this.addMapping("description", BaseClientRepresentation::getDescription, BaseClientRepresentation::setDescription, ClientModel::getDescription, ClientModel::setDescription);
this.addMapping("displayName", BaseClientRepresentation::getDisplayName, BaseClientRepresentation::setDisplayName, ClientModel::getName, ClientModel::setName);
this.addMapping("appUrl", BaseClientRepresentation::getAppUrl, BaseClientRepresentation::setAppUrl, ClientModel::getBaseUrl, ClientModel::setBaseUrl);
Expand All @@ -91,6 +92,7 @@ public BaseClientRepresentation fromModel(ClientModel model, Set<String> include
stream = stream.filter(e -> includeFields.contains(e.getKey()));
}
stream.forEach(e -> e.getValue().fromModel(model, rep));
rep.clearExplicitlySetFields();

return rep;
}
Expand All @@ -101,6 +103,13 @@ public void toModel(BaseClientRepresentation rep, ClientModel existingModel) {
fields.values().forEach(m -> m.toModel(rep, existingModel));
}

@Override
public void toModel(BaseClientRepresentation rep, ClientModel existingModel, Set<String> excludedFields) {
fields.entrySet().stream()
.filter(e -> !excludedFields.contains(e.getKey()))
.forEach(e -> e.getValue().toModel(rep, existingModel));
}

@SuppressWarnings("unchecked")
public void applyProjection(BaseClientRepresentation rep, Set<String> includeFields) {
if (includeFields == null || includeFields.isEmpty()) return;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
package org.keycloak.models.mapper;

import java.util.Set;

import org.keycloak.models.ClientModel;
import org.keycloak.representations.admin.v2.BaseClientRepresentation;

/**
* @author Vaclav Muzikar <vmuzikar@redhat.com>
*/
public interface ClientModelMapper extends RepModelMapper<BaseClientRepresentation, ClientModel> {
default void toModel(BaseClientRepresentation rep, ClientModel model, Set<String> excludedFields) {
toModel(rep, model);
}
}
Comment thread
arnabnandy7 marked this conversation as resolved.
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ protected OIDCClientRepresentation createClientRepresentation() {

public OIDCClientModelMapper() {
addMapping("loginFlows", OIDCClientRepresentation::getLoginFlows, OIDCClientRepresentation::setLoginFlows, model -> createLoginFlows(model), (model, flows) -> setModelFromFlows(flows, model));
addMapping("auth", OIDCClientRepresentation::getAuth, OIDCClientRepresentation::setAuth, model -> getAuth(model), (model, auth) -> setAuth(model, auth));
addMapping("auth", OIDCClientRepresentation::getAuth, OIDCClientRepresentation::setAuth, model -> getAuth(model), this::setAuth);
addMapping("webOrigins", OIDCClientRepresentation::getWebOrigins, OIDCClientRepresentation::setWebOrigins, model -> new LinkedHashSet<>(model.getWebOrigins()), (model, webOrigins) -> model.setWebOrigins(new LinkedHashSet<>(webOrigins)));
addMapping("serviceAccountRoles", OIDCClientRepresentation::getServiceAccountRoles, OIDCClientRepresentation::setServiceAccountRoles, model -> getServiceAccountRoles(model), null);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

public class ServiceException extends RuntimeException {
private Response.Status suggestedHttpResponseStatus;
private Object[] parameters;

public ServiceException(String message) {
super(message);
Expand All @@ -21,6 +22,11 @@ public ServiceException(String message, Response.Status suggestedStatus) {
this.suggestedHttpResponseStatus = suggestedStatus;
}

public ServiceException(String message, Object[] parameters, Response.Status suggestedStatus) {
this(message, suggestedStatus);
this.parameters = parameters == null ? null : parameters.clone();
}
Comment thread
arnabnandy7 marked this conversation as resolved.

public ServiceException(Response.Status suggestedStatus) {
super();
this.suggestedHttpResponseStatus = suggestedStatus;
Expand All @@ -30,6 +36,10 @@ public Optional<Response.Status> getSuggestedResponseStatus() {
return Optional.ofNullable(suggestedHttpResponseStatus);
}

public Optional<Object[]> getParameters() {
return Optional.ofNullable(parameters == null ? null : parameters.clone());
}
Comment thread
arnabnandy7 marked this conversation as resolved.

public WebApplicationException toWebApplicationException() {
return toWebApplicationException(Response.Status.BAD_REQUEST);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
package org.keycloak.services;

import java.util.Optional;

import jakarta.ws.rs.core.Context;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.ext.ExceptionMapper;
import jakarta.ws.rs.ext.Provider;

import org.keycloak.models.KeycloakSession;
import org.keycloak.representations.idm.ErrorRepresentation;
import org.keycloak.services.error.KeycloakErrorHandler;

/**
Expand All @@ -21,6 +25,15 @@ public class ServiceExceptionMapper implements ExceptionMapper<ServiceException>

@Override
public Response toResponse(ServiceException exception) {
return KeycloakErrorHandler.getResponse(session, exception.toWebApplicationException());
Response response = KeycloakErrorHandler.getResponse(session, exception.toWebApplicationException());
Optional<Object[]> parameters = exception.getParameters();
if (exception.getMessage() != null && parameters.isPresent()
&& response.getMediaType() != null && MediaType.APPLICATION_JSON_TYPE.isCompatible(response.getMediaType())) {
ErrorRepresentation error = new ErrorRepresentation();
error.setErrorMessage(exception.getMessage());
error.setParams(parameters.get());
return Response.fromResponse(response).entity(error).build();
}
return response;
}
Comment thread
arnabnandy7 marked this conversation as resolved.
}
Loading
Loading