Instead of an InputStream that doesn't know about its encoding, use a String

Closes #20916

Signed-off-by: Alexander Schwartz <aschwart@redhat.com>
This commit is contained in:
Alexander Schwartz 2024-03-07 11:24:36 +01:00 committed by GitHub
parent b45963012f
commit 595959398b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
18 changed files with 122 additions and 100 deletions

View file

@ -52,6 +52,7 @@ import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory; import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator; import javax.xml.validation.Validator;
import java.io.InputStream; import java.io.InputStream;
import java.io.StringReader;
import java.net.URI; import java.net.URI;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -559,6 +560,16 @@ public class StaxParserUtil {
return xmlEventReader; return xmlEventReader;
} }
public static XMLEventReader getXMLEventReader(String xml) {
XMLInputFactory xmlInputFactory;
xmlInputFactory = XML_INPUT_FACTORY.get();
try {
return xmlInputFactory.createXMLEventReader(new StringReader(xml));
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
private static AtomicBoolean XML_EVENT_READER_ON_SOURCE_SUPPORTED = new AtomicBoolean(true); private static AtomicBoolean XML_EVENT_READER_ON_SOURCE_SUPPORTED = new AtomicBoolean(true);
/** /**

View file

@ -16,7 +16,6 @@
*/ */
package org.keycloak.saml.processing.core.saml.v2.util; package org.keycloak.saml.processing.core.saml.v2.util;
import java.io.InputStream;
import java.security.cert.X509Certificate; import java.security.cert.X509Certificate;
import java.util.List; import java.util.List;
import java.util.function.Function; import java.util.function.Function;
@ -31,6 +30,7 @@ import org.keycloak.saml.common.constants.JBossSAMLURIConstants;
import org.keycloak.saml.common.exceptions.ConfigurationException; import org.keycloak.saml.common.exceptions.ConfigurationException;
import org.keycloak.saml.common.exceptions.ParsingException; import org.keycloak.saml.common.exceptions.ParsingException;
import org.keycloak.saml.common.exceptions.ProcessingException; import org.keycloak.saml.common.exceptions.ProcessingException;
import org.keycloak.saml.common.util.StaxParserUtil;
import org.keycloak.saml.processing.core.parsers.saml.SAMLParser; import org.keycloak.saml.processing.core.parsers.saml.SAMLParser;
import org.keycloak.saml.processing.core.util.XMLSignatureUtil; import org.keycloak.saml.processing.core.util.XMLSignatureUtil;
import org.w3c.dom.Element; import org.w3c.dom.Element;
@ -106,8 +106,8 @@ public class SAMLMetadataUtil {
return null; return null;
} }
public static EntityDescriptorType parseEntityDescriptorType(InputStream inputStream) throws ParsingException { public static EntityDescriptorType parseEntityDescriptorType(String descriptor) throws ParsingException {
Object parsedObject = SAMLParser.getInstance().parse(inputStream); Object parsedObject = SAMLParser.getInstance().parse(StaxParserUtil.getXMLEventReader(descriptor));
EntityDescriptorType entityType; EntityDescriptorType entityType;
if (EntitiesDescriptorType.class.isInstance(parsedObject)) { if (EntitiesDescriptorType.class.isInstance(parsedObject)) {

View file

@ -20,7 +20,6 @@ import org.keycloak.Config;
import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory; import org.keycloak.models.KeycloakSessionFactory;
import java.io.InputStream;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
@ -50,7 +49,7 @@ public abstract class AbstractIdentityProviderFactory<T extends IdentityProvider
} }
@Override @Override
public Map<String, String> parseConfig(KeycloakSession session, InputStream inputStream) { public Map<String, String> parseConfig(KeycloakSession session, String config) {
return new HashMap<>(); return new HashMap<>();
} }
} }

View file

@ -54,10 +54,10 @@ public interface IdentityProviderFactory<T extends IdentityProvider> extends Pro
* <code>inputStream</code>.</p> * <code>inputStream</code>.</p>
* *
* @param session * @param session
* @param inputStream The input stream from where configuration will be loaded from.. * @param config The configuration for the provider
* @return * @return
*/ */
Map<String, String> parseConfig(KeycloakSession session, InputStream inputStream); Map<String, String> parseConfig(KeycloakSession session, String config);
/** /**
* <p>Creates a provider specific {@link IdentityProviderModel} instance. * <p>Creates a provider specific {@link IdentityProviderModel} instance.

View file

@ -21,6 +21,7 @@ import org.keycloak.provider.Provider;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.CloseableHttpClient;
/** /**
@ -50,11 +51,43 @@ public interface HttpClientProvider extends Provider {
public int postText(String uri, String text) throws IOException; public int postText(String uri, String text) throws IOException;
/** /**
* Helper method * Helper method to retrieve the contents of a URL as a String.
* Decoding response with the correct character set is performed according to the headers returned in the server's response.
* To retrieve binary data, use {@link #getInputStream(String)}
* *
* @param uri * @param uri URI with data to receive.
* @return response stream, you must close this stream or leaks will happen * @return Body of the response as a String.
* @throws IOException On network errors, no content being returned or a non-2xx HTTP status code * @throws IOException On network errors, no content being returned or a non-2xx HTTP status code
*/ */
public InputStream get(String uri) throws IOException; String getString(String uri) throws IOException;
/**
* Helper method to retrieve the contents of a URL as an InputStream.
* Use this to retrieve binary data where no additional HTTP headers need to be considered.
* The caller is required to close the returned InputStream to prevent a resource leak.
* <p>
* To retrieve strings that depend on their encoding, use {@link #getString(String)}
*
* @param uri URI with data to receive.
* @return Body of the response as an InputStream. The caller is required to close the returned InputStream to prevent a resource leak.
* @throws IOException On network errors, no content being returned or a non-2xx HTTP status code.
*/
InputStream getInputStream(String uri) throws IOException;
/**
* Helper method.
* The caller is required to close the returned InputStream to prevent a resource leak.
* @deprecated For String content, use {@link #getString(String)}, for binary data use {@link #getInputStream(String)}.
* To be removed in Keycloak 27.
*
* @param uri URI with data to receive.
* @return Body of the response as an InputStream. The caller is required to close the returned InputStream to prevent a resource leak.
* @throws IOException On network errors, no content being returned or a non-2xx HTTP status code.
*/
@Deprecated
default InputStream get(String uri) throws IOException {
return getInputStream(uri);
}
} }

View file

@ -20,7 +20,6 @@ import org.keycloak.broker.provider.AbstractIdentityProviderFactory;
import org.keycloak.models.IdentityProviderModel; import org.keycloak.models.IdentityProviderModel;
import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSession;
import java.io.InputStream;
import java.util.Map; import java.util.Map;
/** /**
@ -46,8 +45,8 @@ public class KeycloakOIDCIdentityProviderFactory extends AbstractIdentityProvide
} }
@Override @Override
public Map<String, String> parseConfig(KeycloakSession session, InputStream inputStream) { public Map<String, String> parseConfig(KeycloakSession session, String config) {
return OIDCIdentityProviderFactory.parseOIDCConfig(session, inputStream); return OIDCIdentityProviderFactory.parseOIDCConfig(session, config);
} }
@Override @Override

View file

@ -23,7 +23,6 @@ import org.keycloak.protocol.oidc.representations.OIDCConfigurationRepresentatio
import org.keycloak.util.JsonSerialization; import org.keycloak.util.JsonSerialization;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.util.Map; import java.util.Map;
/** /**
@ -54,14 +53,14 @@ public class OIDCIdentityProviderFactory extends AbstractIdentityProviderFactory
} }
@Override @Override
public Map<String, String> parseConfig(KeycloakSession session, InputStream inputStream) { public Map<String, String> parseConfig(KeycloakSession session, String config) {
return parseOIDCConfig(session, inputStream); return parseOIDCConfig(session, config);
} }
protected static Map<String, String> parseOIDCConfig(KeycloakSession session, InputStream inputStream) { protected static Map<String, String> parseOIDCConfig(KeycloakSession session, String configString) {
OIDCConfigurationRepresentation rep; OIDCConfigurationRepresentation rep;
try { try {
rep = JsonSerialization.readValue(inputStream, OIDCConfigurationRepresentation.class); rep = JsonSerialization.readValue(configString, OIDCConfigurationRepresentation.class);
} catch (IOException e) { } catch (IOException e) {
throw new RuntimeException("failed to load openid connect metadata", e); throw new RuntimeException("failed to load openid connect metadata", e);
} }

View file

@ -16,7 +16,6 @@
*/ */
package org.keycloak.broker.saml; package org.keycloak.broker.saml;
import java.io.InputStream;
import java.util.Date; import java.util.Date;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
@ -69,9 +68,9 @@ public class SAMLIdentityProviderFactory extends AbstractIdentityProviderFactory
} }
@Override @Override
public Map<String, String> parseConfig(KeycloakSession session, InputStream inputStream) { public Map<String, String> parseConfig(KeycloakSession session, String config) {
try { try {
EntityDescriptorType entityType = SAMLMetadataUtil.parseEntityDescriptorType(inputStream); EntityDescriptorType entityType = SAMLMetadataUtil.parseEntityDescriptorType(config);
IDPSSODescriptorType idpDescriptor = SAMLMetadataUtil.locateIDPSSODescriptorType(entityType); IDPSSODescriptorType idpDescriptor = SAMLMetadataUtil.locateIDPSSODescriptorType(entityType);
if (idpDescriptor != null) { if (idpDescriptor != null) {

View file

@ -23,6 +23,8 @@ import org.apache.http.client.entity.EntityBuilder;
import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType; import org.apache.http.entity.ContentType;
import org.apache.http.impl.client.AbstractResponseHandler;
import org.apache.http.impl.client.BasicResponseHandler;
import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.CloseableHttpClient;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
import org.keycloak.Config; import org.keycloak.Config;
@ -75,6 +77,21 @@ public class DefaultHttpClientFactory implements HttpClientFactory {
private volatile CloseableHttpClient httpClient; private volatile CloseableHttpClient httpClient;
private Config.Scope config; private Config.Scope config;
private final BasicResponseHandler stringResponseHandler = new BasicResponseHandler();
private final InputStreamResponseHandler inputStreamResponseHandler = new InputStreamResponseHandler();
private static class InputStreamResponseHandler extends AbstractResponseHandler<InputStream> {
public InputStream handleEntity(HttpEntity entity) throws IOException {
return entity.getContent();
}
public InputStream handleResponse(HttpResponse response) throws IOException {
return super.handleResponse(response);
}
}
@Override @Override
public HttpClientProvider create(KeycloakSession session) { public HttpClientProvider create(KeycloakSession session) {
lazyInit(session); lazyInit(session);
@ -107,20 +124,25 @@ public class DefaultHttpClientFactory implements HttpClientFactory {
} }
@Override @Override
public InputStream get(String uri) throws IOException { public String getString(String uri) throws IOException {
HttpGet request = new HttpGet(uri); HttpGet request = new HttpGet(uri);
HttpResponse response = httpClient.execute(request); HttpResponse response = httpClient.execute(request);
int statusCode = response.getStatusLine().getStatusCode(); String body = stringResponseHandler.handleResponse(response);
HttpEntity entity = response.getEntity(); if (body == null) {
if (statusCode < 200 || statusCode >= 300) {
EntityUtils.consumeQuietly(entity);
throw new IOException("Unexpected HTTP status code " + response.getStatusLine().getStatusCode() + " when expecting 2xx");
}
if (entity == null) {
throw new IOException("No content returned from HTTP call"); throw new IOException("No content returned from HTTP call");
} }
return entity.getContent(); return body;
}
@Override
public InputStream getInputStream(String uri) throws IOException {
HttpGet request = new HttpGet(uri);
HttpResponse response = httpClient.execute(request);
InputStream body = inputStreamResponseHandler.handleResponse(response);
if (body == null) {
throw new IOException("No content returned from HTTP call");
}
return body;
} }
}; };
} }

View file

@ -20,7 +20,6 @@ package org.keycloak.protocol.oidc.endpoints.request;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
import org.keycloak.OAuth2Constants; import org.keycloak.OAuth2Constants;
import org.keycloak.common.Profile; import org.keycloak.common.Profile;
import org.keycloak.common.util.StreamUtil;
import org.keycloak.connections.httpclient.HttpClientProvider; import org.keycloak.connections.httpclient.HttpClientProvider;
import org.keycloak.events.Errors; import org.keycloak.events.Errors;
import org.keycloak.events.EventBuilder; import org.keycloak.events.EventBuilder;
@ -39,7 +38,6 @@ import org.keycloak.util.TokenUtil;
import jakarta.ws.rs.core.MultivaluedMap; import jakarta.ws.rs.core.MultivaluedMap;
import jakarta.ws.rs.core.Response; import jakarta.ws.rs.core.Response;
import java.io.InputStream;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
@ -98,12 +96,10 @@ public class AuthorizationEndpointRequestParserProcessor {
if (requestUri == null) { if (requestUri == null) {
throw new RuntimeException("Specified 'request_uri' not allowed for this client."); throw new RuntimeException("Specified 'request_uri' not allowed for this client.");
} }
try (InputStream is = session.getProvider(HttpClientProvider.class).get(requestUri)) { String retrievedRequest = session.getProvider(HttpClientProvider.class).getString(requestUri);
String retrievedRequest = StreamUtil.readString(is);
new AuthzEndpointRequestObjectParser(session, retrievedRequest, client).parseRequest(request); new AuthzEndpointRequestObjectParser(session, retrievedRequest, client).parseRequest(request);
} }
} }
}
if (Profile.isFeatureEnabled(Profile.Feature.DYNAMIC_SCOPES)) { if (Profile.isFeatureEnabled(Profile.Feature.DYNAMIC_SCOPES)) {
request.authorizationRequestContext = AuthorizationContextUtil.getAuthorizationRequestContextFromScopes(session, request.getScope()); request.authorizationRequestContext = AuthorizationContextUtil.getAuthorizationRequestContextFromScopes(session, request.getScope());

View file

@ -19,7 +19,6 @@
package org.keycloak.protocol.oidc.grants.ciba.endpoints.request; package org.keycloak.protocol.oidc.grants.ciba.endpoints.request;
import org.keycloak.OAuthErrorException; import org.keycloak.OAuthErrorException;
import org.keycloak.common.util.StreamUtil;
import org.keycloak.connections.httpclient.HttpClientProvider; import org.keycloak.connections.httpclient.HttpClientProvider;
import org.keycloak.events.EventBuilder; import org.keycloak.events.EventBuilder;
import org.keycloak.models.CibaConfig; import org.keycloak.models.CibaConfig;
@ -32,7 +31,6 @@ import org.keycloak.services.ErrorResponseException;
import jakarta.ws.rs.core.MultivaluedMap; import jakarta.ws.rs.core.MultivaluedMap;
import jakarta.ws.rs.core.Response; import jakarta.ws.rs.core.Response;
import java.io.InputStream;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
@ -70,11 +68,9 @@ public class BackchannelAuthenticationEndpointRequestParserProcessor {
throw new RuntimeException("Specified 'request_uri' not allowed for this client."); throw new RuntimeException("Specified 'request_uri' not allowed for this client.");
} }
try (InputStream is = session.getProvider(HttpClientProvider.class).get(requestUri)) { String retrievedRequest = session.getProvider(HttpClientProvider.class).getString(requestUri);
String retrievedRequest = StreamUtil.readString(is);
new BackchannelAuthenticationEndpointSignedRequestParser(session, retrievedRequest, client, config).parseRequest(request); new BackchannelAuthenticationEndpointSignedRequestParser(session, retrievedRequest, client, config).parseRequest(request);
} }
}
return request; return request;

View file

@ -16,7 +16,6 @@
*/ */
package org.keycloak.protocol.oidc.par.endpoints.request; package org.keycloak.protocol.oidc.par.endpoints.request;
import java.io.InputStream;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
@ -24,7 +23,6 @@ import jakarta.ws.rs.core.MultivaluedMap;
import jakarta.ws.rs.core.Response; import jakarta.ws.rs.core.Response;
import org.keycloak.common.Profile; import org.keycloak.common.Profile;
import org.keycloak.common.util.StreamUtil;
import org.keycloak.connections.httpclient.HttpClientProvider; import org.keycloak.connections.httpclient.HttpClientProvider;
import org.keycloak.events.Errors; import org.keycloak.events.Errors;
import org.keycloak.events.EventBuilder; import org.keycloak.events.EventBuilder;
@ -89,11 +87,9 @@ public class ParEndpointRequestParserProcessor {
if (requestUri == null) { if (requestUri == null) {
throw new RuntimeException("Specified 'request_uri' not allowed for this client."); throw new RuntimeException("Specified 'request_uri' not allowed for this client.");
} }
try (InputStream is = session.getProvider(HttpClientProvider.class).get(requestUri)) { String retrievedRequest = session.getProvider(HttpClientProvider.class).getString(requestUri);
String retrievedRequest = StreamUtil.readString(is);
new ParEndpointRequestObjectParser(session, retrievedRequest, client).parseRequest(request); new ParEndpointRequestObjectParser(session, retrievedRequest, client).parseRequest(request);
} }
}
if (Profile.isFeatureEnabled(Profile.Feature.DYNAMIC_SCOPES)) { if (Profile.isFeatureEnabled(Profile.Feature.DYNAMIC_SCOPES)) {
request.setAuthorizationRequestContext(AuthorizationContextUtil.getAuthorizationRequestContextFromScopes(session, request.getScope())); request.setAuthorizationRequestContext(AuthorizationContextUtil.getAuthorizationRequestContextFromScopes(session, request.getScope()));

View file

@ -17,14 +17,12 @@
package org.keycloak.protocol.oidc.utils; package org.keycloak.protocol.oidc.utils;
import org.keycloak.common.util.StreamUtil;
import org.keycloak.connections.httpclient.HttpClientProvider; import org.keycloak.connections.httpclient.HttpClientProvider;
import org.keycloak.jose.jwk.JSONWebKeySet; import org.keycloak.jose.jwk.JSONWebKeySet;
import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSession;
import org.keycloak.util.JsonSerialization; import org.keycloak.util.JsonSerialization;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
/** /**
* *
@ -33,9 +31,7 @@ import java.io.InputStream;
public class JWKSHttpUtils { public class JWKSHttpUtils {
public static JSONWebKeySet sendJwksRequest(KeycloakSession session, String jwksURI) throws IOException { public static JSONWebKeySet sendJwksRequest(KeycloakSession session, String jwksURI) throws IOException {
try (InputStream is = session.getProvider(HttpClientProvider.class).get(jwksURI)){ String keySetString = session.getProvider(HttpClientProvider.class).getString(jwksURI);
String keySetString = StreamUtil.readString(is);
return JsonSerialization.readValue(keySetString, JSONWebKeySet.class); return JsonSerialization.readValue(keySetString, JSONWebKeySet.class);
} }
}
} }

View file

@ -9,7 +9,6 @@ import org.keycloak.protocol.oidc.mappers.PairwiseSubMapperHelper;
import org.keycloak.util.JsonSerialization; import org.keycloak.util.JsonSerialization;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.net.URI; import java.net.URI;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.util.ArrayList; import java.util.ArrayList;
@ -90,21 +89,15 @@ public class PairwiseSubMapperValidator {
} }
private static Set<String> getSectorRedirects(KeycloakSession session, String sectorIdentifierUri) throws ProtocolMapperConfigException { private static Set<String> getSectorRedirects(KeycloakSession session, String sectorIdentifierUri) throws ProtocolMapperConfigException {
InputStream is = null;
try { try {
is = session.getProvider(HttpClientProvider.class).get(sectorIdentifierUri); List<String> sectorRedirects = JsonSerialization.readValue(
List<String> sectorRedirects = JsonSerialization.readValue(is, TypedList.class); session.getProvider(HttpClientProvider.class).getString(sectorIdentifierUri),
TypedList.class
);
return new HashSet<>(sectorRedirects); return new HashSet<>(sectorRedirects);
} catch (IOException e) { } catch (IOException e) {
throw new ProtocolMapperConfigException("Failed to get redirect URIs from the Sector Identifier URI.", throw new ProtocolMapperConfigException("Failed to get redirect URIs from the Sector Identifier URI.",
PAIRWISE_FAILED_TO_GET_REDIRECT_URIS, e); PAIRWISE_FAILED_TO_GET_REDIRECT_URIS, e);
} finally {
if (is != null) {
try {
is.close();
} catch (IOException ignored) {
}
}
} }
} }

View file

@ -16,7 +16,6 @@
*/ */
package org.keycloak.protocol.saml; package org.keycloak.protocol.saml;
import java.io.InputStream;
import java.security.cert.X509Certificate; import java.security.cert.X509Certificate;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -55,14 +54,14 @@ public abstract class SamlAbstractMetadataPublicKeyLoader implements PublicKeyLo
this.forIdP = forIdP; this.forIdP = forIdP;
} }
protected abstract InputStream openInputStream() throws Exception; protected abstract String getKeys() throws Exception;
@Override @Override
public PublicKeysWrapper loadKeys() throws Exception { public PublicKeysWrapper loadKeys() throws Exception {
InputStream inputStream = openInputStream(); String descriptor = getKeys();
List<KeyDescriptorType> keyDescriptor; List<KeyDescriptorType> keyDescriptor;
EntityDescriptorType entityType = SAMLMetadataUtil.parseEntityDescriptorType(inputStream); EntityDescriptorType entityType = SAMLMetadataUtil.parseEntityDescriptorType(descriptor);
if (forIdP) { if (forIdP) {
IDPSSODescriptorType idpDescriptor = SAMLMetadataUtil.locateIDPSSODescriptorType(entityType); IDPSSODescriptorType idpDescriptor = SAMLMetadataUtil.locateIDPSSODescriptorType(entityType);
keyDescriptor = idpDescriptor != null? idpDescriptor.getKeyDescriptor() : null; keyDescriptor = idpDescriptor != null? idpDescriptor.getKeyDescriptor() : null;

View file

@ -16,7 +16,6 @@
*/ */
package org.keycloak.protocol.saml; package org.keycloak.protocol.saml;
import java.io.InputStream;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
import org.keycloak.connections.httpclient.HttpClientProvider; import org.keycloak.connections.httpclient.HttpClientProvider;
import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSession;
@ -44,8 +43,8 @@ public class SamlMetadataPublicKeyLoader extends SamlAbstractMetadataPublicKeyLo
} }
@Override @Override
protected InputStream openInputStream() throws Exception { protected String getKeys() throws Exception {
logger.debugf("loading keys from metadata endpoint %s", metadataUrl); logger.debugf("loading keys from metadata endpoint %s", metadataUrl);
return session.getProvider(HttpClientProvider.class).get(metadataUrl); return session.getProvider(HttpClientProvider.class).getString(metadataUrl);
} }
} }

View file

@ -25,6 +25,7 @@ import org.jboss.resteasy.reactive.NoCache;
import org.keycloak.broker.provider.IdentityProvider; 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.util.StreamUtil;
import org.keycloak.connections.httpclient.HttpClientProvider; import org.keycloak.connections.httpclient.HttpClientProvider;
import org.keycloak.events.admin.OperationType; import org.keycloak.events.admin.OperationType;
import org.keycloak.events.admin.ResourceType; import org.keycloak.events.admin.ResourceType;
@ -56,7 +57,6 @@ import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.MultivaluedMap; import jakarta.ws.rs.core.MultivaluedMap;
import jakarta.ws.rs.core.Response; import jakarta.ws.rs.core.Response;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.util.Comparator; import java.util.Comparator;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
@ -108,9 +108,6 @@ public class IdentityProvidersResource {
/** /**
* Import identity provider from uploaded JSON file * Import identity provider from uploaded JSON file
*
* @return
* @throws IOException
*/ */
@POST @POST
@Path("import-config") @Path("import-config")
@ -125,10 +122,9 @@ public class IdentityProvidersResource {
throw new BadRequestException(); throw new BadRequestException();
} }
String providerId = formDataMap.getFirst("providerId").asString(); String providerId = formDataMap.getFirst("providerId").asString();
InputStream inputStream = formDataMap.getFirst("file").asInputStream(); String config = StreamUtil.readString(formDataMap.getFirst("file").asInputStream());
IdentityProviderFactory providerFactory = getProviderFactoryById(providerId); IdentityProviderFactory<?> providerFactory = getProviderFactoryById(providerId);
Map<String, String> config = providerFactory.parseConfig(session, inputStream); return providerFactory.parseConfig(session, config);
return config;
} }
/** /**
@ -154,20 +150,12 @@ public class IdentityProvidersResource {
String providerId = data.get("providerId").toString(); String providerId = data.get("providerId").toString();
String from = data.get("fromUrl").toString(); String from = data.get("fromUrl").toString();
InputStream inputStream = session.getProvider(HttpClientProvider.class).get(from); String file = session.getProvider(HttpClientProvider.class).getString(from);
try {
IdentityProviderFactory providerFactory = getProviderFactoryById(providerId); IdentityProviderFactory providerFactory = getProviderFactoryById(providerId);
Map<String, String> config; Map<String, String> config = providerFactory.parseConfig(session, file);
config = providerFactory.parseConfig(session, inputStream);
// add the URL just if needed by the identity provider // add the URL just if needed by the identity provider
config.put(IdentityProviderModel.METADATA_DESCRIPTOR_URL, from); config.put(IdentityProviderModel.METADATA_DESCRIPTOR_URL, from);
return config; return config;
} finally {
try {
inputStream.close();
} catch (IOException e) {
}
}
} }
/** /**

View file

@ -16,9 +16,6 @@
*/ */
package org.keycloak.protocol.saml; package org.keycloak.protocol.saml;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.security.Key; import java.security.Key;
import java.security.KeyManagementException; import java.security.KeyManagementException;
import java.security.cert.X509Certificate; import java.security.cert.X509Certificate;
@ -135,8 +132,8 @@ public class SamlMetadataKeyLocatorTest {
} }
@Override @Override
protected InputStream openInputStream() throws Exception { protected String getKeys() throws Exception {
return new ByteArrayInputStream(descriptor.getBytes(StandardCharsets.UTF_8)); return descriptor;
} }
} }