Move some server related logic from info representation classes to server codebase

Signed-off-by: mposolda <mposolda@gmail.com>
This commit is contained in:
mposolda 2024-06-25 12:06:56 +02:00 committed by Marek Posolda
parent e5a4c94f75
commit 3c3f59f861
7 changed files with 121 additions and 117 deletions

View file

@ -17,11 +17,7 @@
package org.keycloak.representations.idm; package org.keycloak.representations.idm;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonProperty;
import org.keycloak.common.util.PemUtils;
import java.security.PublicKey;
/** /**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@ -42,9 +38,6 @@ public class PublishedRealmRepresentation {
@JsonProperty("tokens-not-before") @JsonProperty("tokens-not-before")
protected int notBefore; protected int notBefore;
@JsonIgnore
protected volatile transient PublicKey publicKey;
public String getRealm() { public String getRealm() {
return realm; return realm;
} }
@ -59,27 +52,6 @@ public class PublishedRealmRepresentation {
public void setPublicKeyPem(String publicKeyPem) { public void setPublicKeyPem(String publicKeyPem) {
this.publicKeyPem = publicKeyPem; this.publicKeyPem = publicKeyPem;
this.publicKey = null;
}
@JsonIgnore
public PublicKey getPublicKey() {
if (publicKey != null) return publicKey;
if (publicKeyPem != null) {
try {
publicKey = PemUtils.decodePublicKey(publicKeyPem);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
return publicKey;
}
@JsonIgnore
public void setPublicKey(PublicKey publicKey) {
this.publicKey = publicKey;
this.publicKeyPem = PemUtils.encodeKey(publicKey);
} }
public String getTokenServiceUrl() { public String getTokenServiceUrl() {

View file

@ -20,11 +20,6 @@
package org.keycloak.representations.info; package org.keycloak.representations.info;
import java.util.List; import java.util.List;
import java.util.stream.Collectors;
import org.keycloak.common.crypto.CryptoIntegration;
import org.keycloak.common.crypto.CryptoProvider;
import org.keycloak.common.util.KeystoreUtil;
/** /**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a> * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
@ -38,20 +33,6 @@ public class CryptoInfoRepresentation {
private List<String> clientSignatureAsymmetricAlgorithms; private List<String> clientSignatureAsymmetricAlgorithms;
public static CryptoInfoRepresentation create(List<String> clientSignatureSymmetricAlgorithms, List<String> clientSignatureAsymmetricAlgorithms) {
CryptoInfoRepresentation info = new CryptoInfoRepresentation();
CryptoProvider cryptoProvider = CryptoIntegration.getProvider();
info.cryptoProvider = cryptoProvider.getClass().getSimpleName();
info.supportedKeystoreTypes = CryptoIntegration.getProvider().getSupportedKeyStoreTypes()
.map(KeystoreUtil.KeystoreFormat::toString)
.collect(Collectors.toList());
info.clientSignatureSymmetricAlgorithms = clientSignatureSymmetricAlgorithms;
info.clientSignatureAsymmetricAlgorithms = clientSignatureAsymmetricAlgorithms;
return info;
}
public String getCryptoProvider() { public String getCryptoProvider() {
return cryptoProvider; return cryptoProvider;
} }

View file

@ -1,41 +1,17 @@
package org.keycloak.representations.info; package org.keycloak.representations.info;
import org.keycloak.common.Profile;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors;
public class FeatureRepresentation { public class FeatureRepresentation {
private String name; private String name;
private String label; private String label;
private Type type; private FeatureType type;
private boolean isEnabled; private boolean isEnabled;
private Set<String> dependencies; private Set<String> dependencies;
public FeatureRepresentation() { public FeatureRepresentation() {
} }
public FeatureRepresentation(Profile.Feature feature, boolean isEnabled) {
this.name = feature.name();
this.label = feature.getLabel();
this.type = Type.valueOf(feature.getType().name());
this.isEnabled = isEnabled;
this.dependencies = feature.getDependencies() != null ?
feature.getDependencies().stream().map(Enum::name).collect(Collectors.toSet()) : Collections.emptySet();
}
public static List<FeatureRepresentation> create() {
List<FeatureRepresentation> featureRepresentationList = new ArrayList<>();
Profile profile = Profile.getInstance();
final Map<Profile.Feature, Boolean> features = profile.getFeatures();
features.forEach((f, enabled) -> featureRepresentationList.add(new FeatureRepresentation(f, enabled)));
return featureRepresentationList;
}
public String getName() { public String getName() {
return name; return name;
} }
@ -52,11 +28,11 @@ public class FeatureRepresentation {
this.label = label; this.label = label;
} }
public Type getType() { public FeatureType getType() {
return type; return type;
} }
public void setType(Type type) { public void setType(FeatureType type) {
this.type = type; this.type = type;
} }
@ -76,12 +52,3 @@ public class FeatureRepresentation {
this.dependencies = dependencies; this.dependencies = dependencies;
} }
} }
enum Type {
DEFAULT,
DISABLED_BY_DEFAULT,
PREVIEW,
PREVIEW_DISABLED_BY_DEFAULT,
EXPERIMENTAL,
DEPRECATED;
}

View file

@ -0,0 +1,32 @@
/*
* Copyright 2024 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.keycloak.representations.info;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
public enum FeatureType {
DEFAULT,
DISABLED_BY_DEFAULT,
PREVIEW,
PREVIEW_DISABLED_BY_DEFAULT,
EXPERIMENTAL,
DEPRECATED;
}

View file

@ -17,12 +17,8 @@
package org.keycloak.representations.info; package org.keycloak.representations.info;
import org.keycloak.common.Profile;
import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
/** /**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a> * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
@ -34,41 +30,36 @@ public class ProfileInfoRepresentation {
private List<String> previewFeatures; private List<String> previewFeatures;
private List<String> experimentalFeatures; private List<String> experimentalFeatures;
public static ProfileInfoRepresentation create() {
ProfileInfoRepresentation info = new ProfileInfoRepresentation();
Profile profile = Profile.getInstance();
info.name = profile.getName().name().toLowerCase();
info.disabledFeatures = names(profile.getDisabledFeatures());
info.previewFeatures = names(profile.getPreviewFeatures());
info.experimentalFeatures = names(profile.getExperimentalFeatures());
return info;
}
public String getName() { public String getName() {
return name; return name;
} }
public void setName(String name) {
this.name = name;
}
public List<String> getDisabledFeatures() { public List<String> getDisabledFeatures() {
return disabledFeatures; return disabledFeatures;
} }
public void setDisabledFeatures(List<String> disabledFeatures) {
this.disabledFeatures = disabledFeatures;
}
public List<String> getPreviewFeatures() { public List<String> getPreviewFeatures() {
return previewFeatures; return previewFeatures;
} }
public void setPreviewFeatures(List<String> previewFeatures) {
this.previewFeatures = previewFeatures;
}
public List<String> getExperimentalFeatures() { public List<String> getExperimentalFeatures() {
return experimentalFeatures; return experimentalFeatures;
} }
private static List<String> names(Set<Profile.Feature> featureSet) { public void setExperimentalFeatures(List<String> experimentalFeatures) {
List<String> l = new LinkedList(); this.experimentalFeatures = experimentalFeatures;
for (Profile.Feature f : featureSet) {
l.add(f.name());
}
return l;
} }
} }

View file

@ -17,7 +17,6 @@
package org.keycloak.representations.info; package org.keycloak.representations.info;
import org.keycloak.common.Version;
import java.util.Date; import java.util.Date;
import java.util.Locale; import java.util.Locale;
@ -43,9 +42,9 @@ public class SystemInfoRepresentation {
private String userTimezone; private String userTimezone;
private String userLocale; private String userLocale;
public static SystemInfoRepresentation create(long serverStartupTime) { public static SystemInfoRepresentation create(long serverStartupTime, String serverVersion) {
SystemInfoRepresentation rep = new SystemInfoRepresentation(); SystemInfoRepresentation rep = new SystemInfoRepresentation();
rep.version = Version.VERSION; rep.version = serverVersion;
rep.serverTime = new Date().toString(); rep.serverTime = new Date().toString();
rep.uptimeMillis = System.currentTimeMillis() - serverStartupTime; rep.uptimeMillis = System.currentTimeMillis() - serverStartupTime;
rep.uptime = formatUptime(rep.uptimeMillis); rep.uptime = formatUptime(rep.uptimeMillis);

View file

@ -25,6 +25,10 @@ import org.keycloak.broker.provider.IdentityProvider;
import org.keycloak.broker.provider.IdentityProviderFactory; import org.keycloak.broker.provider.IdentityProviderFactory;
import org.keycloak.broker.social.SocialIdentityProvider; import org.keycloak.broker.social.SocialIdentityProvider;
import org.keycloak.common.Profile; import org.keycloak.common.Profile;
import org.keycloak.common.Version;
import org.keycloak.common.crypto.CryptoIntegration;
import org.keycloak.common.crypto.CryptoProvider;
import org.keycloak.common.util.KeystoreUtil;
import org.keycloak.component.ComponentFactory; import org.keycloak.component.ComponentFactory;
import org.keycloak.crypto.ClientSignatureVerifierProvider; import org.keycloak.crypto.ClientSignatureVerifierProvider;
import org.keycloak.events.EventType; import org.keycloak.events.EventType;
@ -50,6 +54,7 @@ import org.keycloak.representations.idm.ProtocolMapperTypeRepresentation;
import org.keycloak.representations.info.ClientInstallationRepresentation; import org.keycloak.representations.info.ClientInstallationRepresentation;
import org.keycloak.representations.info.CryptoInfoRepresentation; import org.keycloak.representations.info.CryptoInfoRepresentation;
import org.keycloak.representations.info.FeatureRepresentation; import org.keycloak.representations.info.FeatureRepresentation;
import org.keycloak.representations.info.FeatureType;
import org.keycloak.representations.info.MemoryInfoRepresentation; import org.keycloak.representations.info.MemoryInfoRepresentation;
import org.keycloak.representations.info.ProfileInfoRepresentation; import org.keycloak.representations.info.ProfileInfoRepresentation;
import org.keycloak.representations.info.ProviderRepresentation; import org.keycloak.representations.info.ProviderRepresentation;
@ -65,6 +70,7 @@ import jakarta.ws.rs.Produces;
import jakarta.ws.rs.WebApplicationException; import jakarta.ws.rs.WebApplicationException;
import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.MediaType;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator; import java.util.Comparator;
@ -73,6 +79,7 @@ import java.util.LinkedHashMap;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
@ -102,10 +109,10 @@ public class ServerInfoAdminResource {
@Operation( summary = "Get themes, social providers, auth providers, and event listeners available on this server") @Operation( summary = "Get themes, social providers, auth providers, and event listeners available on this server")
public ServerInfoRepresentation getInfo() { public ServerInfoRepresentation getInfo() {
ServerInfoRepresentation info = new ServerInfoRepresentation(); ServerInfoRepresentation info = new ServerInfoRepresentation();
info.setSystemInfo(SystemInfoRepresentation.create(session.getKeycloakSessionFactory().getServerStartupTimestamp())); info.setSystemInfo(SystemInfoRepresentation.create(session.getKeycloakSessionFactory().getServerStartupTimestamp(), Version.VERSION));
info.setMemoryInfo(MemoryInfoRepresentation.create()); info.setMemoryInfo(MemoryInfoRepresentation.create());
info.setProfileInfo(ProfileInfoRepresentation.create()); info.setProfileInfo(createProfileInfo());
info.setFeatures(FeatureRepresentation.create()); info.setFeatures(createFeatureRepresentations());
// True - asymmetric algorithms, false - symmetric algorithms // True - asymmetric algorithms, false - symmetric algorithms
Map<Boolean, List<String>> algorithms = session.getAllProviders(ClientSignatureVerifierProvider.class).stream() Map<Boolean, List<String>> algorithms = session.getAllProviders(ClientSignatureVerifierProvider.class).stream()
@ -122,7 +129,7 @@ public class ServerInfoAdminResource {
HashMap::new HashMap::new
) )
); );
info.setCryptoInfo(CryptoInfoRepresentation.create(algorithms.get(false), algorithms.get(true))); info.setCryptoInfo(createCryptoInfo(algorithms.get(false), algorithms.get(true)));
setSocialProviders(info); setSocialProviders(info);
setIdentityProviders(info); setIdentityProviders(info);
@ -224,10 +231,10 @@ public class ServerInfoAdminResource {
} }
} }
} }
private LinkedList<String> filterThemes(Theme.Type type, LinkedList<String> themeNames) { private LinkedList<String> filterThemes(Theme.Type type, LinkedList<String> themeNames) {
LinkedList<String> filteredNames = new LinkedList<>(themeNames); LinkedList<String> filteredNames = new LinkedList<>(themeNames);
boolean filterAdminV2 = (type == Theme.Type.ADMIN) && boolean filterAdminV2 = (type == Theme.Type.ADMIN) &&
!Profile.isFeatureEnabled(Profile.Feature.ADMIN2); !Profile.isFeatureEnabled(Profile.Feature.ADMIN2);
boolean filterLoginV2 = (type == Theme.Type.LOGIN) && boolean filterLoginV2 = (type == Theme.Type.LOGIN) &&
!Profile.isFeatureEnabled(Profile.Feature.LOGIN2); !Profile.isFeatureEnabled(Profile.Feature.LOGIN2);
@ -237,13 +244,13 @@ public class ServerInfoAdminResource {
filteredNames.remove("rh-sso.v2"); filteredNames.remove("rh-sso.v2");
} }
boolean filterAccountV3 = (type == Theme.Type.ACCOUNT) && boolean filterAccountV3 = (type == Theme.Type.ACCOUNT) &&
!Profile.isFeatureEnabled(Profile.Feature.ACCOUNT3); !Profile.isFeatureEnabled(Profile.Feature.ACCOUNT3);
if (filterAccountV3) { if (filterAccountV3) {
filteredNames.remove("keycloak.v3"); filteredNames.remove("keycloak.v3");
} }
return filteredNames; return filteredNames;
} }
@ -384,4 +391,59 @@ public class ServerInfoAdminResource {
return m; return m;
} }
private ProfileInfoRepresentation createProfileInfo() {
ProfileInfoRepresentation info = new ProfileInfoRepresentation();
Profile profile = Profile.getInstance();
info.setName(profile.getName().name().toLowerCase());
info.setDisabledFeatures(names(profile.getDisabledFeatures()));
info.setPreviewFeatures(names(profile.getPreviewFeatures()));
info.setExperimentalFeatures(names(profile.getExperimentalFeatures()));
return info;
}
private static List<String> names(Set<Profile.Feature> featureSet) {
List<String> l = new LinkedList();
for (Profile.Feature f : featureSet) {
l.add(f.name());
}
return l;
}
private static FeatureRepresentation getFeatureRep(Profile.Feature feature, boolean isEnabled) {
FeatureRepresentation featureRep = new FeatureRepresentation();
featureRep.setName(feature.name());
featureRep.setLabel(feature.getLabel());
featureRep.setType(FeatureType.valueOf(feature.getType().name()));
featureRep.setEnabled(isEnabled);
featureRep.setDependencies(feature.getDependencies() != null ?
feature.getDependencies().stream().map(Enum::name).collect(Collectors.toSet()) : Collections.emptySet());
return featureRep;
}
private static List<FeatureRepresentation> createFeatureRepresentations() {
List<FeatureRepresentation> featureRepresentationList = new ArrayList<>();
Profile profile = Profile.getInstance();
final Map<Profile.Feature, Boolean> features = profile.getFeatures();
features.forEach((f, enabled) -> featureRepresentationList.add(getFeatureRep(f, enabled)));
return featureRepresentationList;
}
private static CryptoInfoRepresentation createCryptoInfo(List<String> clientSignatureSymmetricAlgorithms, List<String> clientSignatureAsymmetricAlgorithms) {
CryptoInfoRepresentation info = new CryptoInfoRepresentation();
CryptoProvider cryptoProvider = CryptoIntegration.getProvider();
info.setCryptoProvider(cryptoProvider.getClass().getSimpleName());
info.setSupportedKeystoreTypes(CryptoIntegration.getProvider().getSupportedKeyStoreTypes()
.map(KeystoreUtil.KeystoreFormat::toString)
.collect(Collectors.toList()));
info.setClientSignatureSymmetricAlgorithms(clientSignatureSymmetricAlgorithms);
info.setClientSignatureAsymmetricAlgorithms(clientSignatureAsymmetricAlgorithms);
return info;
}
} }