Skip to content

Commit

Permalink
KEYCLOAK-5342 (#4431)
Browse files Browse the repository at this point in the history
  • Loading branch information
stianst committed Aug 28, 2017
1 parent 794c508 commit 8cc1d02
Show file tree
Hide file tree
Showing 12 changed files with 169 additions and 123 deletions.
Expand Up @@ -36,5 +36,7 @@
<module name="org.apache.httpcomponents"/> <module name="org.apache.httpcomponents"/>
<module name="org.jboss.resteasy.resteasy-jaxrs"/> <module name="org.jboss.resteasy.resteasy-jaxrs"/>
<module name="javax.transaction.api"/> <module name="javax.transaction.api"/>
<module name="com.fasterxml.jackson.core.jackson-databind"/>
<module name="com.fasterxml.jackson.core.jackson-core"/>
</dependencies> </dependencies>
</module> </module>
Expand Up @@ -17,16 +17,25 @@


package org.keycloak.broker.provider.util; package org.keycloak.broker.provider.util;


import org.apache.http.*; import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.http.Header;
import org.apache.http.HeaderIterator;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient; import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.entity.UrlEncodedFormEntity;
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.client.methods.HttpRequestBase; import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.client.utils.URIBuilder; import org.apache.http.client.utils.URIBuilder;
import org.apache.http.entity.StringEntity;
import org.apache.http.message.BasicNameValuePair; import org.apache.http.message.BasicNameValuePair;
import org.keycloak.connections.httpclient.HttpClientProvider; import org.keycloak.connections.httpclient.HttpClientProvider;
import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSession;
import org.keycloak.util.JsonSerialization;


import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
Expand All @@ -47,25 +56,36 @@
*/ */
public class SimpleHttp { public class SimpleHttp {


private KeycloakSession session; private static final ObjectMapper mapper = new ObjectMapper();

private HttpClient client;


private String url; private String url;
private String method; private String method;
private Map<String, String> headers; private Map<String, String> headers;
private Map<String, String> params; private Map<String, String> params;
private Object entity;


protected SimpleHttp(String url, String method, KeycloakSession session) { protected SimpleHttp(String url, String method, HttpClient client) {
this.session = session; this.client = client;
this.url = url; this.url = url;
this.method = method; this.method = method;
} }


public static SimpleHttp doGet(String url, KeycloakSession session) { public static SimpleHttp doGet(String url, KeycloakSession session) {
return new SimpleHttp(url, "GET", session); return doGet(url, session.getProvider(HttpClientProvider.class).getHttpClient());
}

public static SimpleHttp doGet(String url, HttpClient client) {
return new SimpleHttp(url, "GET", client);
} }


public static SimpleHttp doPost(String url, KeycloakSession session) { public static SimpleHttp doPost(String url, KeycloakSession session) {
return new SimpleHttp(url, "POST", session); return doPost(url, session.getProvider(HttpClientProvider.class).getHttpClient());
}

public static SimpleHttp doPost(String url, HttpClient client) {
return new SimpleHttp(url, "POST", client);
} }


public SimpleHttp header(String name, String value) { public SimpleHttp header(String name, String value) {
Expand All @@ -76,6 +96,11 @@ public SimpleHttp header(String name, String value) {
return this; return this;
} }


public SimpleHttp json(Object entity) {
this.entity = entity;
return this;
}

public SimpleHttp param(String name, String value) { public SimpleHttp param(String name, String value) {
if (params == null) { if (params == null) {
params = new HashMap<String, String>(); params = new HashMap<String, String>();
Expand All @@ -84,43 +109,52 @@ public SimpleHttp param(String name, String value) {
return this; return this;
} }


public String asString() throws IOException { public SimpleHttp auth(String token) {
HttpClient httpClient = session.getProvider(HttpClientProvider.class).getHttpClient(); header("Authorization", "Bearer " + token);

return this;
HttpResponse response = makeRequest(httpClient); }

InputStream is;
HttpEntity entity = response.getEntity();
if (entity != null) {
is = entity.getContent();
try {
HeaderIterator it = response.headerIterator();
while (it.hasNext()) {
Header header = it.nextHeader();
if (header.getName().equals("Content-Encoding") && header.getValue().equals("gzip")) {
is = new GZIPInputStream(is);
}
}


return toString(is); public SimpleHttp acceptJson() {
} finally { if (headers == null || !headers.containsKey("Accept")) {
if (is != null) { header("Accept", "application/json");
is.close();
}
}
} }
return null; return this;
} }


public int asStatus() throws IOException { public JsonNode asJson() throws IOException {
HttpClient httpClient = session.getProvider(HttpClientProvider.class).getHttpClient(); if (headers == null || !headers.containsKey("Accept")) {
header("Accept", "application/json");
}
return mapper.readTree(asString());
}

public <T> T asJson(Class<T> type) throws IOException {
if (headers == null || !headers.containsKey("Accept")) {
header("Accept", "application/json");
}
return JsonSerialization.readValue(asString(), type);
}

public <T> T asJson(TypeReference<T> type) throws IOException {
if (headers == null || !headers.containsKey("Accept")) {
header("Accept", "application/json");
}
return JsonSerialization.readValue(asString(), type);
}

public String asString() throws IOException {
return asResponse().asString();
}


HttpResponse response = makeRequest(httpClient); public int asStatus() throws IOException {
return asResponse().getStatus();
}


return response.getStatusLine().getStatusCode(); public Response asResponse() throws IOException {
return makeRequest();
} }


private HttpResponse makeRequest(HttpClient httpClient) throws IOException { private Response makeRequest() throws IOException {
boolean get = method.equals("GET"); boolean get = method.equals("GET");
boolean post = method.equals("POST"); boolean post = method.equals("POST");


Expand All @@ -130,7 +164,16 @@ private HttpResponse makeRequest(HttpClient httpClient) throws IOException {
} }


if (post) { if (post) {
((HttpPost) httpRequest).setEntity(getFormEntityFromParameter()); if (params != null) {
((HttpPost) httpRequest).setEntity(getFormEntityFromParameter());
} else if (entity != null) {
if (headers == null || !headers.containsKey("Content-Type")) {
header("Content-Type", "application/json");
}
((HttpPost) httpRequest).setEntity(getJsonEntity());
} else {
throw new IllegalStateException("No content set");
}
} }


if (headers != null) { if (headers != null) {
Expand All @@ -139,7 +182,7 @@ private HttpResponse makeRequest(HttpClient httpClient) throws IOException {
} }
} }


return httpClient.execute(httpRequest); return new Response(client.execute(httpRequest));
} }


private URI appendParameterToUrl(String url) throws IOException { private URI appendParameterToUrl(String url) throws IOException {
Expand All @@ -161,28 +204,93 @@ private URI appendParameterToUrl(String url) throws IOException {
return uri; return uri;
} }


private StringEntity getJsonEntity() throws IOException {
return new StringEntity(JsonSerialization.writeValueAsString(entity));
}

private UrlEncodedFormEntity getFormEntityFromParameter() throws IOException{ private UrlEncodedFormEntity getFormEntityFromParameter() throws IOException{
List<NameValuePair> urlParameters = new ArrayList<>(); List<NameValuePair> urlParameters = new ArrayList<>();


if (params != null) { if (params != null) {
for (Map.Entry<String, String> p : params.entrySet()) { for (Map.Entry<String, String> p : params.entrySet()) {
urlParameters.add(new BasicNameValuePair(p.getKey(), p.getValue())); urlParameters. add(new BasicNameValuePair(p.getKey(), p.getValue()));
} }
} }


return new UrlEncodedFormEntity(urlParameters); return new UrlEncodedFormEntity(urlParameters);
} }


private String toString(InputStream is) throws IOException { public static class Response {
InputStreamReader reader = new InputStreamReader(is);
private HttpResponse response;
private int statusCode = -1;
private String responseString;

public Response(HttpResponse response) {
this.response = response;
}

private void readResponse() throws IOException {
if (statusCode == -1) {
statusCode = response.getStatusLine().getStatusCode();

InputStream is;
HttpEntity entity = response.getEntity();
if (entity != null) {
is = entity.getContent();
try {
HeaderIterator it = response.headerIterator();
while (it.hasNext()) {
Header header = it.nextHeader();
if (header.getName().equals("Content-Encoding") && header.getValue().equals("gzip")) {
is = new GZIPInputStream(is);
}
}

InputStreamReader reader = new InputStreamReader(is);

StringWriter writer = new StringWriter();

char[] buffer = new char[1024 * 4];
for (int n = reader.read(buffer); n != -1; n = reader.read(buffer)) {
writer.write(buffer, 0, n);
}

responseString = writer.toString();
} finally {
if (is != null) {
is.close();
}
}
}
}
}


StringWriter writer = new StringWriter(); public int getStatus() throws IOException {
readResponse();
return response.getStatusLine().getStatusCode();
}

public JsonNode asJson() throws IOException {
return mapper.readTree(asString());
}


char[] buffer = new char[1024 * 4]; public <T> T asJson(Class<T> type) throws IOException {
for (int n = reader.read(buffer); n != -1; n = reader.read(buffer)) { return JsonSerialization.readValue(asString(), type);
writer.write(buffer, 0, n);
} }


return writer.toString(); public <T> T asJson(TypeReference<T> type) throws IOException {
return JsonSerialization.readValue(asString(), type);
}

public String asString() throws IOException {
readResponse();
return responseString;
}

public void close() throws IOException {
readResponse();
}
} }

} }
Expand Up @@ -20,7 +20,6 @@
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
import org.keycloak.OAuth2Constants; import org.keycloak.OAuth2Constants;
import org.keycloak.broker.oidc.mappers.AbstractJsonUserAttributeMapper; import org.keycloak.broker.oidc.mappers.AbstractJsonUserAttributeMapper;
import org.keycloak.broker.oidc.util.JsonSimpleHttp;
import org.keycloak.broker.provider.AuthenticationRequest; import org.keycloak.broker.provider.AuthenticationRequest;
import org.keycloak.broker.provider.BrokeredIdentityContext; import org.keycloak.broker.provider.BrokeredIdentityContext;
import org.keycloak.broker.provider.IdentityBrokerException; import org.keycloak.broker.provider.IdentityBrokerException;
Expand Down Expand Up @@ -137,7 +136,7 @@ protected void backchannelLogout(UserSessionModel userSession, String idToken) {
logoutUri.queryParam("id_token_hint", idToken); logoutUri.queryParam("id_token_hint", idToken);
String url = logoutUri.build().toString(); String url = logoutUri.build().toString();
try { try {
int status = JsonSimpleHttp.doGet(url, session).asStatus(); int status = SimpleHttp.doGet(url, session).asStatus();
boolean success = status >=200 && status < 400; boolean success = status >=200 && status < 400;
if (!success) { if (!success) {
logger.warn("Failed backchannel broker logout to: " + url); logger.warn("Failed backchannel broker logout to: " + url);
Expand Down Expand Up @@ -368,9 +367,8 @@ protected BrokeredIdentityContext extractIdentity(AccessTokenResponse tokenRespo
if (!getConfig().isDisableUserInfoService()) { if (!getConfig().isDisableUserInfoService()) {
String userInfoUrl = getUserInfoUrl(); String userInfoUrl = getUserInfoUrl();
if (userInfoUrl != null && !userInfoUrl.isEmpty() && (id == null || name == null || preferredUsername == null || email == null)) { if (userInfoUrl != null && !userInfoUrl.isEmpty() && (id == null || name == null || preferredUsername == null || email == null)) {
SimpleHttp request = JsonSimpleHttp.doGet(userInfoUrl, session) JsonNode userInfo = SimpleHttp.doGet(userInfoUrl, session)
.header("Authorization", "Bearer " + accessToken); .header("Authorization", "Bearer " + accessToken).asJson();
JsonNode userInfo = JsonSimpleHttp.asJson(request);


id = getJsonProperty(userInfo, "sub"); id = getJsonProperty(userInfo, "sub");
name = getJsonProperty(userInfo, "name"); name = getJsonProperty(userInfo, "name");
Expand Down

This file was deleted.

Expand Up @@ -21,7 +21,6 @@
import org.keycloak.broker.oidc.AbstractOAuth2IdentityProvider; import org.keycloak.broker.oidc.AbstractOAuth2IdentityProvider;
import org.keycloak.broker.oidc.OAuth2IdentityProviderConfig; import org.keycloak.broker.oidc.OAuth2IdentityProviderConfig;
import org.keycloak.broker.oidc.mappers.AbstractJsonUserAttributeMapper; import org.keycloak.broker.oidc.mappers.AbstractJsonUserAttributeMapper;
import org.keycloak.broker.oidc.util.JsonSimpleHttp;
import org.keycloak.broker.provider.BrokeredIdentityContext; import org.keycloak.broker.provider.BrokeredIdentityContext;
import org.keycloak.broker.provider.IdentityBrokerException; import org.keycloak.broker.provider.IdentityBrokerException;
import org.keycloak.broker.provider.util.SimpleHttp; import org.keycloak.broker.provider.util.SimpleHttp;
Expand Down Expand Up @@ -54,7 +53,7 @@ public BitbucketIdentityProvider(KeycloakSession session, OAuth2IdentityProvider
@Override @Override
protected BrokeredIdentityContext doGetFederatedIdentity(String accessToken) { protected BrokeredIdentityContext doGetFederatedIdentity(String accessToken) {
try { try {
JsonNode profile = JsonSimpleHttp.asJson(SimpleHttp.doGet(USER_URL, session).header("Authorization", "Bearer " + accessToken)); JsonNode profile = SimpleHttp.doGet(USER_URL, session).header("Authorization", "Bearer " + accessToken).asJson();


String type = getJsonProperty(profile, "type"); String type = getJsonProperty(profile, "type");
if (type == null) { if (type == null) {
Expand Down

0 comments on commit 8cc1d02

Please sign in to comment.