Move UserFederatedStorageProvider into legacy module

Closes #13627
This commit is contained in:
Alexander Schwartz 2022-08-17 10:12:09 +02:00 committed by Hynek Mlnařík
parent 962a685b7b
commit 1d2d3e5ca5
29 changed files with 227 additions and 158 deletions

View file

@ -22,18 +22,11 @@ import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import org.keycloak.authorization.AuthorizationProvider;
import org.keycloak.authorization.AuthorizationProviderFactory;
import org.keycloak.authorization.model.Policy;
import org.keycloak.authorization.model.Resource;
import org.keycloak.authorization.model.ResourceServer;
import org.keycloak.authorization.model.Scope;
import org.keycloak.authorization.store.PolicyStore;
import org.keycloak.authorization.store.StoreFactory;
import org.keycloak.common.Profile;
import org.keycloak.common.Version;
import org.keycloak.common.util.MultivaluedHashMap;
import org.keycloak.credential.CredentialModel;
import org.keycloak.exportimport.ExportOptions;
import org.keycloak.models.ClientModel;
import org.keycloak.models.ClientScopeModel;
import org.keycloak.models.FederatedIdentityModel;
@ -53,18 +46,11 @@ import org.keycloak.representations.idm.RolesRepresentation;
import org.keycloak.representations.idm.ScopeMappingRepresentation;
import org.keycloak.representations.idm.UserConsentRepresentation;
import org.keycloak.representations.idm.UserRepresentation;
import org.keycloak.representations.idm.authorization.PolicyRepresentation;
import org.keycloak.representations.idm.authorization.ResourceOwnerRepresentation;
import org.keycloak.representations.idm.authorization.ResourceRepresentation;
import org.keycloak.representations.idm.authorization.ResourceServerRepresentation;
import org.keycloak.representations.idm.authorization.ScopeRepresentation;
import org.keycloak.storage.federated.UserFederatedStorageProvider;
import org.keycloak.util.JsonSerialization;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
@ -293,118 +279,15 @@ public class ExportUtils {
ClientRepresentation clientRep = ModelToRepresentation.toRepresentation(client, session);
clientRep.setSecret(client.getSecret());
if (Profile.isFeatureEnabled(Profile.Feature.AUTHORIZATION)) {
clientRep.setAuthorizationSettings(exportAuthorizationSettings(session, client));
clientRep.setAuthorizationSettings(ModelToRepresentation.toResourceServerRepresentation(session, client));
}
return clientRep;
}
public static ResourceServerRepresentation exportAuthorizationSettings(KeycloakSession session, ClientModel client) {
AuthorizationProviderFactory providerFactory = (AuthorizationProviderFactory) session.getKeycloakSessionFactory().getProviderFactory(AuthorizationProvider.class);
AuthorizationProvider authorization = providerFactory.create(session, client.getRealm());
StoreFactory storeFactory = authorization.getStoreFactory();
ResourceServer settingsModel = authorization.getStoreFactory().getResourceServerStore().findByClient(client);
if (settingsModel == null) {
return null;
}
ResourceServerRepresentation representation = toRepresentation(settingsModel, client);
representation.setId(null);
representation.setName(null);
representation.setClientId(null);
List<ResourceRepresentation> resources = storeFactory.getResourceStore().findByResourceServer(settingsModel)
.stream().map(resource -> {
ResourceRepresentation rep = toRepresentation(resource, settingsModel, authorization);
if (rep.getOwner().getId().equals(settingsModel.getClientId())) {
rep.setOwner((ResourceOwnerRepresentation) null);
} else {
rep.getOwner().setId(null);
}
rep.getScopes().forEach(scopeRepresentation -> {
scopeRepresentation.setId(null);
scopeRepresentation.setIconUri(null);
});
return rep;
}).collect(Collectors.toList());
representation.setResources(resources);
List<PolicyRepresentation> policies = new ArrayList<>();
PolicyStore policyStore = storeFactory.getPolicyStore();
policies.addAll(policyStore.findByResourceServer(settingsModel)
.stream().filter(policy -> !policy.getType().equals("resource") && !policy.getType().equals("scope") && policy.getOwner() == null)
.map(policy -> createPolicyRepresentation(authorization, policy)).collect(Collectors.toList()));
policies.addAll(policyStore.findByResourceServer(settingsModel)
.stream().filter(policy -> (policy.getType().equals("resource") || policy.getType().equals("scope") && policy.getOwner() == null))
.map(policy -> createPolicyRepresentation(authorization, policy)).collect(Collectors.toList()));
representation.setPolicies(policies);
List<ScopeRepresentation> scopes = storeFactory.getScopeStore().findByResourceServer(settingsModel).stream().map(scope -> {
ScopeRepresentation rep = toRepresentation(scope);
rep.setPolicies(null);
rep.setResources(null);
return rep;
}).collect(Collectors.toList());
representation.setScopes(scopes);
return representation;
}
private static PolicyRepresentation createPolicyRepresentation(AuthorizationProvider authorizationProvider, Policy policy) {
try {
PolicyRepresentation rep = toRepresentation(policy, authorizationProvider, true, true);
Map<String, String> config = new HashMap<>(rep.getConfig());
rep.setConfig(config);
Set<Scope> scopes = policy.getScopes();
if (!scopes.isEmpty()) {
List<String> scopeNames = scopes.stream().map(Scope::getName).collect(Collectors.toList());
config.put("scopes", JsonSerialization.writeValueAsString(scopeNames));
}
Set<Resource> policyResources = policy.getResources();
if (!policyResources.isEmpty()) {
List<String> resourceNames = policyResources.stream().map(Resource::getName).collect(Collectors.toList());
config.put("resources", JsonSerialization.writeValueAsString(resourceNames));
}
Set<Policy> associatedPolicies = policy.getAssociatedPolicies();
if (!associatedPolicies.isEmpty()) {
config.put("applyPolicies", JsonSerialization.writeValueAsString(associatedPolicies.stream().map(associated -> associated.getName()).collect(Collectors.toList())));
}
return rep;
} catch (Exception e) {
throw new RuntimeException("Error while exporting policy [" + policy.getName() + "].", e);
}
}
public static List<RoleRepresentation> exportRoles(Stream<RoleModel> roles) {
return roles.map(ExportUtils::exportRole).collect(Collectors.toList());
}
public static List<String> getRoleNames(Collection<RoleModel> roles) {
List<String> roleNames = new ArrayList<>();
for (RoleModel role : roles) {
roleNames.add(role.getName());
}
return roleNames;
}
/**
* Full export of role including composite roles
* @param role

View file

@ -21,6 +21,9 @@ import org.jboss.logging.Logger;
import org.keycloak.common.enums.SslRequired;
import org.keycloak.common.util.MultivaluedHashMap;
import org.keycloak.component.ComponentModel;
import org.keycloak.exportimport.ExportAdapter;
import org.keycloak.exportimport.ExportOptions;
import org.keycloak.exportimport.util.ExportUtils;
import org.keycloak.keys.KeyProvider;
import org.keycloak.migration.MigrationProvider;
import org.keycloak.migration.migrators.MigrateTo8_0_0;
@ -89,8 +92,10 @@ import org.keycloak.storage.UserStorageProviderModel;
import org.keycloak.storage.UserStorageUtil;
import org.keycloak.storage.federated.UserFederatedStorageProvider;
import org.keycloak.userprofile.UserProfileProvider;
import org.keycloak.util.JsonSerialization;
import org.keycloak.validation.ValidationUtil;
import javax.ws.rs.core.MediaType;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
@ -108,6 +113,7 @@ import static org.keycloak.models.utils.RepresentationToModel.createGroups;
import static org.keycloak.models.utils.RepresentationToModel.createRoleMappings;
import static org.keycloak.models.utils.RepresentationToModel.importGroup;
import static org.keycloak.models.utils.RepresentationToModel.importRoles;
import static org.keycloak.models.utils.StripSecretsUtils.stripForExport;
/**
* This wraps the functionality about export/import for legacy storage. This will be handled differently for the new map storage,
@ -123,6 +129,16 @@ public class LegacyExportImportManager implements ExportImportManager {
this.session = session;
}
public void exportRealm(RealmModel realm, ExportOptions options, ExportAdapter callback) {
callback.setType(MediaType.APPLICATION_JSON);
callback.writeToOutputStream(outputStream -> {
RealmRepresentation rep = ExportUtils.exportRealm(session, realm, options, false);
stripForExport(session, rep);
JsonSerialization.writeValueToStream(outputStream, rep);
outputStream.close();
});
}
@Override
public void importRealm(RealmRepresentation rep, RealmModel newRealm, boolean skipUserDependent) {
convertDeprecatedSocialProviders(rep);

View file

@ -16,3 +16,4 @@
#
org.keycloak.storage.UserStorageProviderSpi
org.keycloak.storage.federated.UserFederatedStorageProviderSpi

View file

@ -21,6 +21,9 @@ import org.jboss.logging.Logger;
import org.keycloak.common.enums.SslRequired;
import org.keycloak.common.util.MultivaluedHashMap;
import org.keycloak.component.ComponentModel;
import org.keycloak.models.ModelException;
import org.keycloak.exportimport.ExportAdapter;
import org.keycloak.exportimport.ExportOptions;
import org.keycloak.keys.KeyProvider;
import org.keycloak.migration.MigrationProvider;
import org.keycloak.migration.migrators.MigrationUtils;
@ -413,6 +416,10 @@ public class MapExportImportManager implements ExportImportManager {
return role;
}
public void exportRealm(RealmModel realm, ExportOptions options, ExportAdapter callback) {
throw new ModelException("exporting for map storage is currently not supported");
}
private static void convertDeprecatedDefaultRoles(RealmRepresentation rep, RealmModel newRealm) {
if (rep.getDefaultRole() == null) {

View file

@ -0,0 +1,49 @@
/*
* Copyright 2022 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.exportimport;
import java.io.IOException;
/**
* This adapter allows the exporter to act independent of APIs used to serve the exported data to the caller.
*
* @author Alexander Schwartz
*/
public interface ExportAdapter {
/**
* Set the mime type of the output.
*
* @param mediaType Mime Type
*/
void setType(String mediaType);
/**
* Write to the output stream. Once writing is complete, close it.
*
* @param consumer A consumer to that accepts the output stream.
*/
void writeToOutputStream(ConsumerOfOutputStream consumer);
/**
* Custom consumer that is allowed to throw an {@link IOException} as writing to an output stream might do this.
*/
@FunctionalInterface
interface ConsumerOfOutputStream {
void accept(java.io.OutputStream t) throws IOException;
}
}

View file

@ -1,4 +1,21 @@
package org.keycloak.exportimport.util;
/*
* Copyright 2022 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.exportimport;
/**
* @author <a href="mailto:mstrukel@redhat.com">Marko Strukelj</a>

View file

@ -19,12 +19,15 @@ package org.keycloak.models.utils;
import org.jboss.logging.Logger;
import org.keycloak.authorization.AuthorizationProvider;
import org.keycloak.authorization.AuthorizationProviderFactory;
import org.keycloak.authorization.model.PermissionTicket;
import org.keycloak.authorization.model.Policy;
import org.keycloak.authorization.model.Resource;
import org.keycloak.authorization.model.ResourceServer;
import org.keycloak.authorization.model.Scope;
import org.keycloak.authorization.policy.provider.PolicyProviderFactory;
import org.keycloak.authorization.store.PolicyStore;
import org.keycloak.authorization.store.StoreFactory;
import org.keycloak.common.Profile;
import org.keycloak.common.util.MultivaluedHashMap;
import org.keycloak.common.util.Time;
@ -1073,4 +1076,100 @@ public class ModelToRepresentation {
return representation;
}
public static ResourceServerRepresentation toResourceServerRepresentation(KeycloakSession session, ClientModel client) {
AuthorizationProviderFactory providerFactory = (AuthorizationProviderFactory) session.getKeycloakSessionFactory().getProviderFactory(AuthorizationProvider.class);
AuthorizationProvider authorization = providerFactory.create(session, client.getRealm());
StoreFactory storeFactory = authorization.getStoreFactory();
ResourceServer settingsModel = authorization.getStoreFactory().getResourceServerStore().findByClient(client);
if (settingsModel == null) {
return null;
}
ResourceServerRepresentation representation = toRepresentation(settingsModel, client);
representation.setId(null);
representation.setName(null);
representation.setClientId(null);
List<ResourceRepresentation> resources = storeFactory.getResourceStore().findByResourceServer(settingsModel)
.stream().map(resource -> {
ResourceRepresentation rep = toRepresentation(resource, settingsModel, authorization);
if (rep.getOwner().getId().equals(settingsModel.getClientId())) {
rep.setOwner((ResourceOwnerRepresentation) null);
} else {
rep.getOwner().setId(null);
}
rep.getScopes().forEach(scopeRepresentation -> {
scopeRepresentation.setId(null);
scopeRepresentation.setIconUri(null);
});
return rep;
}).collect(Collectors.toList());
representation.setResources(resources);
List<PolicyRepresentation> policies = new ArrayList<>();
PolicyStore policyStore = storeFactory.getPolicyStore();
policies.addAll(policyStore.findByResourceServer(settingsModel)
.stream().filter(policy -> !policy.getType().equals("resource") && !policy.getType().equals("scope") && policy.getOwner() == null)
.map(policy -> toRepresentation(authorization, policy)).collect(Collectors.toList()));
policies.addAll(policyStore.findByResourceServer(settingsModel)
.stream().filter(policy -> (policy.getType().equals("resource") || policy.getType().equals("scope") && policy.getOwner() == null))
.map(policy -> toRepresentation(authorization, policy)).collect(Collectors.toList()));
representation.setPolicies(policies);
List<ScopeRepresentation> scopes = storeFactory.getScopeStore().findByResourceServer(settingsModel).stream().map(scope -> {
ScopeRepresentation rep = toRepresentation(scope);
rep.setPolicies(null);
rep.setResources(null);
return rep;
}).collect(Collectors.toList());
representation.setScopes(scopes);
return representation;
}
private static PolicyRepresentation toRepresentation(AuthorizationProvider authorizationProvider, Policy policy) {
try {
PolicyRepresentation rep = toRepresentation(policy, authorizationProvider, true, true);
Map<String, String> config = new HashMap<>(rep.getConfig());
rep.setConfig(config);
Set<Scope> scopes = policy.getScopes();
if (!scopes.isEmpty()) {
List<String> scopeNames = scopes.stream().map(Scope::getName).collect(Collectors.toList());
config.put("scopes", JsonSerialization.writeValueAsString(scopeNames));
}
Set<Resource> policyResources = policy.getResources();
if (!policyResources.isEmpty()) {
List<String> resourceNames = policyResources.stream().map(Resource::getName).collect(Collectors.toList());
config.put("resources", JsonSerialization.writeValueAsString(resourceNames));
}
Set<Policy> associatedPolicies = policy.getAssociatedPolicies();
if (!associatedPolicies.isEmpty()) {
config.put("applyPolicies", JsonSerialization.writeValueAsString(associatedPolicies.stream().map(associated -> associated.getName()).collect(Collectors.toList())));
}
return rep;
} catch (Exception e) {
throw new RuntimeException("Error while exporting policy [" + policy.getName() + "].", e);
}
}
}

View file

@ -112,7 +112,6 @@ import org.keycloak.representations.idm.authorization.ResourceRepresentation;
import org.keycloak.representations.idm.authorization.ResourceServerRepresentation;
import org.keycloak.representations.idm.authorization.ScopeRepresentation;
import org.keycloak.storage.DatastoreProvider;
import org.keycloak.storage.federated.UserFederatedStorageProvider;
import org.keycloak.util.JsonSerialization;
import static org.keycloak.protocol.saml.util.ArtifactBindingUtils.computeArtifactBindingIdentifierString;

View file

@ -89,7 +89,7 @@ public class StripSecretsUtils {
return rep;
}
public static RealmRepresentation stripForExport(KeycloakSession session, RealmRepresentation rep) {
public static void stripForExport(KeycloakSession session, RealmRepresentation rep) {
strip(rep);
List<ClientRepresentation> clients = rep.getClients();
@ -127,8 +127,6 @@ public class StripSecretsUtils {
strip(u);
}
}
return rep;
}
public static UserRepresentation strip(UserRepresentation user) {

View file

@ -17,6 +17,8 @@
package org.keycloak.storage;
import org.keycloak.exportimport.ExportAdapter;
import org.keycloak.exportimport.ExportOptions;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;
import org.keycloak.representations.idm.RealmRepresentation;
@ -33,4 +35,6 @@ public interface ExportImportManager {
void updateRealm(RealmRepresentation rep, RealmModel realm);
UserModel createUser(RealmModel realm, UserRepresentation userRep);
void exportRealm(RealmModel realm, ExportOptions options, ExportAdapter callback);
}

View file

@ -17,7 +17,6 @@
org.keycloak.component.ComponentFactorySpi
org.keycloak.provider.ExceptionConverterSpi
org.keycloak.storage.federated.UserFederatedStorageProviderSpi
org.keycloak.models.ClientSpi
org.keycloak.models.ClientScopeSpi
org.keycloak.models.GroupSpi

View file

@ -22,7 +22,6 @@ import org.keycloak.provider.InvalidationHandler.InvalidableObjectType;
import org.keycloak.provider.Provider;
import org.keycloak.services.clientpolicy.ClientPolicyManager;
import org.keycloak.sessions.AuthenticationSessionProvider;
import org.keycloak.storage.federated.UserFederatedStorageProvider;
import org.keycloak.vault.VaultTranscriber;
import java.util.Set;
@ -302,15 +301,6 @@ public interface KeycloakSession {
@Deprecated
RoleProvider roleLocalStorage();
/**
* Hybrid storage for UserStorageProviders that can't store a specific piece of keycloak data in their external storage.
* No cache in front.
*
* @deprecated Access to the legacy store is no longer possible via this method. Adjust your code according to the Keycloak 19 Upgrading Guide.
*/
@Deprecated
UserFederatedStorageProvider userFederatedStorage();
/**
* Key manager
*

View file

@ -36,7 +36,6 @@ import org.keycloak.authorization.AuthorizationProvider;
import org.keycloak.authorization.model.ResourceServer;
import org.keycloak.events.admin.OperationType;
import org.keycloak.events.admin.ResourceType;
import org.keycloak.exportimport.util.ExportUtils;
import org.keycloak.models.ClientModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.UserModel;
@ -124,7 +123,7 @@ public class ResourceServerService {
@Produces("application/json")
public Response exportSettings() {
this.auth.realm().requireManageAuthorization();
return Response.ok(ExportUtils.exportAuthorizationSettings(session, client)).build();
return Response.ok(ModelToRepresentation.toResourceServerRepresentation(session, client)).build();
}
@Path("/import")

View file

@ -48,7 +48,6 @@ import org.keycloak.services.clientpolicy.ClientPolicyManager;
import org.keycloak.models.LegacySessionSupportProvider;
import org.keycloak.sessions.AuthenticationSessionProvider;
import org.keycloak.storage.DatastoreProvider;
import org.keycloak.storage.federated.UserFederatedStorageProvider;
import org.keycloak.vault.DefaultVaultTranscriber;
import org.keycloak.vault.VaultProvider;
import org.keycloak.vault.VaultTranscriber;
@ -83,7 +82,6 @@ public class DefaultKeycloakSession implements KeycloakSession {
private UserSessionProvider sessionProvider;
private UserLoginFailureProvider userLoginFailureProvider;
private AuthenticationSessionProvider authenticationSessionProvider;
private UserFederatedStorageProvider userFederatedStorageProvider;
private final KeycloakContext context;
private KeyManager keyManager;
private ThemeManager themeManager;
@ -164,15 +162,6 @@ public class DefaultKeycloakSession implements KeycloakSession {
return factory;
}
@Override
@Deprecated
public UserFederatedStorageProvider userFederatedStorage() {
if (userFederatedStorageProvider == null) {
userFederatedStorageProvider = getProvider(UserFederatedStorageProvider.class);
}
return userFederatedStorageProvider;
}
@Override
@Deprecated
public UserProvider userLocalStorage() {

View file

@ -17,7 +17,6 @@
package org.keycloak.services.resources.admin;
import static org.keycloak.utils.LockObjectsForModification.lockUserSessionsForModification;
import static org.keycloak.models.utils.StripSecretsUtils.stripForExport;
import static org.keycloak.util.JsonSerialization.readValue;
import java.security.cert.X509Certificate;
@ -48,6 +47,7 @@ import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import javax.ws.rs.core.StreamingOutput;
import com.fasterxml.jackson.core.type.TypeReference;
@ -71,8 +71,8 @@ import org.keycloak.events.admin.OperationType;
import org.keycloak.events.admin.ResourceType;
import org.keycloak.exportimport.ClientDescriptionConverter;
import org.keycloak.exportimport.ClientDescriptionConverterFactory;
import org.keycloak.exportimport.util.ExportOptions;
import org.keycloak.exportimport.util.ExportUtils;
import org.keycloak.exportimport.ExportAdapter;
import org.keycloak.exportimport.ExportOptions;
import org.keycloak.models.ClientModel;
import org.keycloak.models.ClientScopeModel;
import org.keycloak.models.Constants;
@ -110,6 +110,8 @@ import org.keycloak.services.resources.admin.ext.AdminRealmResourceProvider;
import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
import org.keycloak.services.resources.admin.permissions.AdminPermissionManagement;
import org.keycloak.services.resources.admin.permissions.AdminPermissions;
import org.keycloak.storage.DatastoreProvider;
import org.keycloak.storage.ExportImportManager;
import org.keycloak.storage.LegacyStoreSyncEvent;
import org.keycloak.utils.ProfileHelper;
import org.keycloak.utils.ReservedCharValidator;
@ -1055,8 +1057,7 @@ public class RealmAdminResource {
*/
@Path("partial-export")
@POST
@Produces(MediaType.APPLICATION_JSON)
public RealmRepresentation partialExport(@QueryParam("exportGroupsAndRoles") Boolean exportGroupsAndRoles,
public Response partialExport(@QueryParam("exportGroupsAndRoles") Boolean exportGroupsAndRoles,
@QueryParam("exportClients") Boolean exportClients) {
auth.realm().requireViewRealm();
@ -1074,8 +1075,22 @@ public class RealmAdminResource {
// this means that if clients is true but groups/roles is false the service account is exported without roles
// the other option is just include service accounts if clientsExported && groupsAndRolesExported
ExportOptions options = new ExportOptions(false, clientsExported, groupsAndRolesExported, clientsExported);
RealmRepresentation rep = ExportUtils.exportRealm(session, realm, options, false);
return stripForExport(session, rep);
ExportImportManager exportProvider = session.getProvider(DatastoreProvider.class).getExportImportManager();
Response.ResponseBuilder response = Response.ok();
exportProvider.exportRealm(realm, options, new ExportAdapter() {
@Override
public void setType(String mediaType) {
response.type(mediaType);
}
@Override
public void writeToOutputStream(ConsumerOfOutputStream consumer) {
response.entity((StreamingOutput) consumer::accept);
}
});
return response.build();
}
@Path("keys")

View file

@ -16,10 +16,8 @@
*/
package org.keycloak.validation;
import org.keycloak.authentication.AuthenticatorUtil;
import org.keycloak.authentication.authenticators.util.LoAUtil;
import org.keycloak.models.ClientModel;
import org.keycloak.models.ClientScopeModel;
import org.keycloak.protocol.ProtocolMapperConfigException;
import org.keycloak.protocol.oidc.OIDCAdvancedConfigWrapper;
import org.keycloak.protocol.oidc.OIDCConfigAttributes;

View file

@ -1768,6 +1768,9 @@ public class PermissionsTest extends AbstractKeycloakTest {
@Test
public void partialExport() {
// re-enable as part of https://github.com/keycloak/keycloak/issues/14291
ProfileAssume.assumeFeatureDisabled(Profile.Feature.MAP_STORAGE);
invoke(new Invocation() {
public void invoke(RealmResource realm) {
realm.partialExport(false, false);

View file

@ -1,7 +1,7 @@
package org.keycloak.testsuite.admin.partialexport;
import java.util.Arrays;
import org.junit.Test;
import org.keycloak.common.Profile;
import org.keycloak.common.util.MultivaluedHashMap;
import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.representations.idm.ComponentExportRepresentation;
@ -12,6 +12,7 @@ import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.representations.idm.RoleRepresentation;
import org.keycloak.representations.idm.ScopeMappingRepresentation;
import org.keycloak.testsuite.Assert;
import org.keycloak.testsuite.ProfileAssume;
import org.keycloak.testsuite.admin.AbstractAdminTest;
import java.util.HashMap;
@ -41,6 +42,8 @@ public class PartialExportTest extends AbstractAdminTest {
@Test
public void testExport() {
// re-enable as part of https://github.com/keycloak/keycloak/issues/14291
ProfileAssume.assumeFeatureDisabled(Profile.Feature.MAP_STORAGE);
// exportGroupsAndRoles == false, exportClients == false
RealmRepresentation rep = adminClient.realm(EXPORT_TEST_REALM).partialExport(false, false);