8000 Client type service account default type by patrickjennings · Pull Request #29037 · keycloak/keycloak · GitHub
[go: up one dir, main page]

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
15 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
< 8000 strong>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 @@ -19,7 +19,9 @@
package org.keycloak.client.clienttype;

import org.keycloak.models.ClientModel;
import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.representations.idm.ClientTypeRepresentation;

import java.util.Map;

/**
* TODO:client-types javadocs
Expand All @@ -41,10 +43,8 @@ public interface ClientType {
<T> T getDefaultValue(String optionName, Class<T> optionType);


// Augment at the client type
// Augment particular client on creation of client (TODO:client-types Should it be clientModel or clientRepresentation? Or something else?)
void onCreate(ClientRepresentation newClient) throws ClientTypeException;
Map<String, ClientTypeRepresentation.PropertyConfig> getConfiguration();

// Augment particular client on update of client (TODO:client-types Should it be clientModel or clientRepresentation? Or something else?)
void onUpdate(ClientModel currentClient, ClientRepresentation clientToUpdate) throws ClientTypeException;
// Augment at the client type
ClientModel augment(ClientModel client);
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
import org.keycloak.models.ProtocolMapperModel;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleModel;
import java.util.List;

import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicMarkableReference;
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,15 @@

package org.keycloak.services.clienttype.client;

import java.util.function.Consumer;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.function.Supplier;
import java.util.stream.Collectors;

import org.keycloak.common.util.ObjectUtil;
import org.keycloak.models.ClientModel;
import org.keycloak.models.delegate.ClientModelLazyDelegate;
import org.keycloak.client.clienttype.ClientType;
import org.keycloak.client.clienttype.ClientTypeException;

/**
* Delegates to client-type and underlying delegate
Expand All @@ -47,45 +48,219 @@ public TypeAwareClientModelDelegate(ClientType clientType, Supplier<ClientModel>

@Override
public boolean isStandardFlowEnabled() {
return getBooleanProperty("standardFlowEnabled", super::isStandardFlowEnabled);
return TypedClientSimpleAttribute.STANDARD_FLOW_ENABLED
.getClientAttribute(clientType, super::isStandardFlowEnabled, Boolean.class);
}

@Override
public void setStandardFlowEnabled(boolean standardFlowEnabled) {
setBooleanProperty("standardFlowEnabled", standardFlowEnabled, super::setStandardFlowEnabled);
TypedClientSimpleAttribute.STANDARD_FLOW_ENABLED
.setClientAttribute(clientType, standardFlowEnabled, super::setStandardFlowEnabled, Boolean.class);
}

@Override
public boolean isBearerOnly() {
return TypedClientSimpleAttribute.BEARER_ONLY
.getClientAttribute(clientType, super::isBearerOnly, Boolean.class);
}

protected boolean getBooleanProperty(String propertyName, Supplier<Boolean> clientGetter) {
// Check if clientType supports the feature. If not, simply return false
if (!clientType.isApplicable(propertyName)) {
return false;
}
@Override
public void setBearerOnly(boolean bearerOnly) {
TypedClientSimpleAttribute.BEARER_ONLY
.setClientAttribute(clientType, bearer 10000 Only, super::setBearerOnly, Boolean.class);
}

@Override
public boolean isConsentRequired() {
return TypedClientSimpleAttribute.CONSENT_REQUIRED
.getClientAttribute(clientType, super::isConsentRequired, Boolean.class);
}

@Override
public void setConsentRequired(boolean consentRequired) {
TypedClientSimpleAttribute.CONSENT_REQUIRED
.setClientAttribute(clientType, consentRequired, super::setConsentRequired, Boolean.class);
}

@Override
public boolean isDirectAccessGrantsEnabled() {
return TypedClientSimpleAttribute.DIRECT_ACCESS_GRANTS_ENABLED
.getClientAttribute(clientType, super::isDirectAccessGrantsEnabled, Boolean.class);
}

@Override
public void setDirectAccessGrantsEnabled(boolean directAccessGrantsEnabled) {
TypedClientSimpleAttribute.DIRECT_ACCESS_GRANTS_ENABLED
.setClientAttribute(clientType, directAccessGrantsEnabled, super::setDirectAccessGrantsEnabled, Boolean.class);
}

@Override
public boolean isAlwaysDisplayInConsole() {
return TypedClientSimpleAttribute.ALWAYS_DISPLAY_IN_CONSOLE
.getClientAttribute(clientType, super::isAlwaysDisplayInConsole, Boolean.class);
}

@Override
public void setAlwaysDisplayInConsole(boolean alwaysDisplayInConsole) {
TypedClientSimpleAttribute.ALWAYS_DISPLAY_IN_CONSOLE
.setClientAttribute(clientType, alwaysDisplayInConsole, super::setAlwaysDisplayInConsole, Boolean.class);
}

@Override
public boolean isFrontchannelLogout() {
return TypedClientSimpleAttribute.FRONTCHANNEL_LOGOUT
.getClientAttribute(clientType, super::isFrontchannelLogout, Boolean.class);
}

@Override
public void setFrontchannelLogout(boolean frontchannelLogout) {
TypedClientSimpleAttribute.FRONTCHANNEL_LOGOUT
.setClientAttribute(clientType, frontchannelLogout, super::setFrontchannelLogout, Boolean.class);
}

@Override
public boolean isImplicitFlowEnabled() {
return TypedClientSimpleAttribute.IMPLICIT_FLOW_ENABLED
.getClientAttribute(clientType, super::isImplicitFlowEnabled, Boolean.class);
}

@Override
public void setImplicitFlowEnabled(boolean implicitFlowEnabled) {
TypedClientSimpleAttribute.IMPLICIT_FLOW_ENABLED
.setClientAttribute(clientType, implicitFlowEnabled, super::setImplicitFlowEnabled, Boolean.class);
}

@Override
public boolean isServiceAccountsEnabled() {
return TypedClientSimpleAttribute.SERVICE_ACCOUNTS_ENABLED
.getClientAttribute(clientType, super::isServiceAccountsEnabled, Boolean.class);
}

@Override
public void setServiceAccountsEnabled(boolean flag) {
TypedClientSimpleAttribute.SERVICE_ACCOUNTS_ENABLED
.setClientAttribute(clientType, flag, super::setServiceAccountsEnabled, Boolean.class);
}

@Override
public String getProtocol() {
return TypedClientSimpleAttribute.PROTOCOL
.getClientAttribute(clientType, super::getProtocol, String.class);
}

@Override
public void setProtocol(String protocol) {
TypedClientSimpleAttribute.PROTOCOL
.setClientAttribute(clientType, protocol, super::setProtocol, String.class);
}

@Override
public boolean isPublicClient() {
return TypedClientSimpleAttribute.PUBLIC_CLIENT
.getClientAttribute(clientType, super::isPublicClient, Boolean.class);
}

@Override
public void setPublicClient(boolean flag) {
TypedClientSimpleAttribute.PUBLIC_CLIENT
.setClientAttribute(clientType, flag, super::setPublicClient, Boolean.class);
}

@Override
public Set<String> getWebOrigins() {
return TypedClientSimpleAttribute.WEB_ORIGINS
.getClientAttribute(clientType, super::getWebOrigins, Set.class);
}

@Override
public void setWebOrigins(Set<String> webOrigins) {
TypedClientSimpleAttribute.WEB_ORIGINS
.setClientAttribute(clientType, webOrigins, super::setWebOrigins, Set.class);
}

@Override
public void addWebOrigin(String webOrigin) {
TypedClientSimpleAttribute.WEB_ORIGINS
.setClientAttribute(clientType, webOrigin, super::addWebOrigin, String.class);
}

@Override
public void removeWebOrigin(String webOrigin) {
TypedClientSimpleAttribute.WEB_ORIGINS
.setClientAttribute(clientType, null, (val) -> super.removeWebOrigin(webOrigin), String.class);
}

// Check if this is read-only. If yes, then we just directly delegate to return stuff from the clientType rather than from client
if (clientType.isReadOnly(propertyName)) {
return clientType.getDefaultValue(propertyName, Boolean.class);
@Override
public Set<String> getRedirectUris() {
return TypedClientSimpleAttribute.REDIRECT_URIS
.getClientAttribute(clientType, super::getRedirectUris, Set.class);
}

@Override
public void setRedirectUris(Set<String> redirectUris) {
TypedClientSimpleAttribute.REDIRECT_URIS
.setClientAttribute(clientType, redirectUris, super::setRedirectUris, Set.class);
}

@Override
public void addRedirectUri(String redirectUri) {
TypedClientSimpleAttribute.REDIRECT_URIS
.setClientAttribute(clientType, redirectUri, super::addRedirectUri, String.class);
}

@Override
public void removeRedirectUri(String redirectUri) {
TypedClientSimpleAttribute.REDIRECT_URIS
.setClientAttribute(clientType, null, (val) -> super.removeRedirectUri(redirectUri), String.class);
}

@Override
public void setAttribute(String name, String value) {
TypedClientExtendedAttribute attribute = TypedClientExtendedAttribute.getAttributesByName().get(name);
if (attribute != null) {
attribute.setClientAttribute(clientType, value, (newValue) -> super.setAttribute(name, newValue), String.class);
} else {
super.setAttribute(name, value);
}
}

// Delegate to clientGetter
return clientGetter.get();
@Override
public void removeAttribute(String name) {
TypedClientExtendedAttribute attribute = TypedClientExtendedAttribute.getAttributesByName().get(name);
if (attribute != null) {
attribute.setClientAttribute(clientType, null, (val) -> super.removeAttribute(name), String.class);
} else {
super.removeAttribute(name);
}
}

protected void setBooleanProperty(String propertyName, Boolean newValue, Consumer<Boolean> clientSetter) {
// Check if clientType supports the feature. If not, return directly
if (!clientType.isApplicable(propertyName)) {
return;
@Override
public String getAttribute(String name) {
TypedClientExtendedAttribute attribute = TypedClientExtendedAttribute.getAttributesByName().get(name);
if (attribute != null) {
return attribute.getClientAttribute(clientType, () -> super.getAttribute(name), String.class);
} else {
return super.getAttribute(name);
}
}

@Override
public Map<String, String> getAttributes() {
// Start with attributes set on the delegate.
Map<String, String> attributes = new HashMap<>(super.getAttributes());

// Get extended client type attributes and values from the client type configuration.
Set<String> extendedClientTypeAttributes =
clientType.getConfiguration().entrySet().stream()
.map(Map.Entry::getKey)
.filter(entry -> TypedClientExtendedAttribute.getAttributesByName().containsKey(entry))
.collect(Collectors.toSet());

// Check if this is read-only. If yes and there is an attempt to change some stuff, then throw an exception
if (clientType.isReadOnly(propertyName)) {
Boolean oldVal = clientType.getDefaultValue(propertyName, Boolean.class);
if (!ObjectUtil.isEqualOrBothNull(oldVal, newValue)) {
throw new ClientTypeException("Property " + propertyName + " of client " + getClientId() + " is read-only due to client type " + clientType.getName());
}
// Augment client type attributes on top of attributes on the delegate.
for (String entry : extendedClientTypeAttributes) {
attributes.put(entry, getAttribute(entry));
}

// Call clientSetter
clientSetter.accept(newValue);
return attributes;
}
}
Loading
0