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:
parent
b45963012f
commit
595959398b
18 changed files with 122 additions and 100 deletions
|
@ -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);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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)) {
|
||||||
|
|
|
@ -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<>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,10 +96,8 @@ 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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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,10 +68,8 @@ 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;
|
||||||
|
|
|
@ -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,10 +87,8 @@ 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)) {
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 = providerFactory.parseConfig(session, file);
|
||||||
Map<String, String> config;
|
// add the URL just if needed by the identity provider
|
||||||
config = providerFactory.parseConfig(session, inputStream);
|
config.put(IdentityProviderModel.METADATA_DESCRIPTOR_URL, from);
|
||||||
// add the URL just if needed by the identity provider
|
return config;
|
||||||
config.put(IdentityProviderModel.METADATA_DESCRIPTOR_URL, from);
|
|
||||||
return config;
|
|
||||||
} finally {
|
|
||||||
try {
|
|
||||||
inputStream.close();
|
|
||||||
} catch (IOException e) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue