keycloak-aplcache
Changes
forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider-oidc.html 9(+8 -1)
forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider-saml.html 9(+8 -1)
Details
diff --git a/broker/core/src/main/java/org/keycloak/broker/provider/AbstractIdentityProvider.java b/broker/core/src/main/java/org/keycloak/broker/provider/AbstractIdentityProvider.java
index a231346..f4ddeae 100755
--- a/broker/core/src/main/java/org/keycloak/broker/provider/AbstractIdentityProvider.java
+++ b/broker/core/src/main/java/org/keycloak/broker/provider/AbstractIdentityProvider.java
@@ -64,6 +64,11 @@ public abstract class AbstractIdentityProvider<C extends IdentityProviderModel>
}
@Override
+ public void backchannelLogout(UserSessionModel userSession, UriInfo uriInfo, RealmModel realm) {
+
+ }
+
+ @Override
public void attachUserSession(UserSessionModel userSession, ClientSessionModel clientSession, BrokeredIdentityContext context) {
}
diff --git a/broker/core/src/main/java/org/keycloak/broker/provider/IdentityProvider.java b/broker/core/src/main/java/org/keycloak/broker/provider/IdentityProvider.java
index 01d5455..2c503bb 100755
--- a/broker/core/src/main/java/org/keycloak/broker/provider/IdentityProvider.java
+++ b/broker/core/src/main/java/org/keycloak/broker/provider/IdentityProvider.java
@@ -76,6 +76,8 @@ public interface IdentityProvider<C extends IdentityProviderModel> extends Provi
*/
Response retrieveToken(FederatedIdentityModel identity);
+ void backchannelLogout(UserSessionModel userSession, UriInfo uriInfo, RealmModel realm);
+
/**
* Called when a Keycloak application initiates a logout through the browser. This is expected to do a logout
* with the IDP
diff --git a/broker/oidc/src/main/java/org/keycloak/broker/oidc/AbstractOAuth2IdentityProvider.java b/broker/oidc/src/main/java/org/keycloak/broker/oidc/AbstractOAuth2IdentityProvider.java
index 95e1f6a..b80949a 100755
--- a/broker/oidc/src/main/java/org/keycloak/broker/oidc/AbstractOAuth2IdentityProvider.java
+++ b/broker/oidc/src/main/java/org/keycloak/broker/oidc/AbstractOAuth2IdentityProvider.java
@@ -22,7 +22,7 @@ import org.codehaus.jackson.map.ObjectMapper;
import org.jboss.logging.Logger;
import org.keycloak.ClientConnection;
import org.keycloak.OAuth2Constants;
-import org.keycloak.broker.oidc.util.SimpleHttp;
+import org.keycloak.broker.provider.util.SimpleHttp;
import org.keycloak.broker.provider.AbstractIdentityProvider;
import org.keycloak.broker.provider.AuthenticationRequest;
import org.keycloak.broker.provider.BrokeredIdentityContext;
diff --git a/broker/oidc/src/main/java/org/keycloak/broker/oidc/KeycloakOIDCIdentityProvider.java b/broker/oidc/src/main/java/org/keycloak/broker/oidc/KeycloakOIDCIdentityProvider.java
index 3c59a96..d791765 100755
--- a/broker/oidc/src/main/java/org/keycloak/broker/oidc/KeycloakOIDCIdentityProvider.java
+++ b/broker/oidc/src/main/java/org/keycloak/broker/oidc/KeycloakOIDCIdentityProvider.java
@@ -1,6 +1,6 @@
package org.keycloak.broker.oidc;
-import org.keycloak.broker.oidc.util.SimpleHttp;
+import org.keycloak.broker.provider.util.SimpleHttp;
import org.keycloak.broker.provider.BrokeredIdentityContext;
import org.keycloak.constants.AdapterConstants;
import org.keycloak.events.EventBuilder;
@@ -74,7 +74,7 @@ public class KeycloakOIDCIdentityProvider extends OIDCIdentityProvider {
&& userSession.getState() != UserSessionModel.State.LOGGING_OUT
&& userSession.getState() != UserSessionModel.State.LOGGED_OUT
) {
- AuthenticationManager.backchannelLogout(session, realm, userSession, uriInfo, clientConnection, headers);
+ AuthenticationManager.backchannelLogout(session, realm, userSession, uriInfo, clientConnection, headers, false);
}
}
diff --git a/broker/oidc/src/main/java/org/keycloak/broker/oidc/OIDCIdentityProvider.java b/broker/oidc/src/main/java/org/keycloak/broker/oidc/OIDCIdentityProvider.java
index b840f37..01e6c41 100755
--- a/broker/oidc/src/main/java/org/keycloak/broker/oidc/OIDCIdentityProvider.java
+++ b/broker/oidc/src/main/java/org/keycloak/broker/oidc/OIDCIdentityProvider.java
@@ -19,7 +19,8 @@ package org.keycloak.broker.oidc;
import org.codehaus.jackson.JsonNode;
import org.jboss.logging.Logger;
-import org.keycloak.broker.oidc.util.SimpleHttp;
+import org.keycloak.broker.oidc.util.JsonSimpleHttp;
+import org.keycloak.broker.provider.util.SimpleHttp;
import org.keycloak.broker.provider.AuthenticationRequest;
import org.keycloak.broker.provider.BrokeredIdentityContext;
import org.keycloak.broker.provider.IdentityBrokerException;
@@ -127,20 +128,51 @@ public class OIDCIdentityProvider extends AbstractOAuth2IdentityProvider<OIDCIde
}
@Override
- public Response keycloakInitiatedBrowserLogout(UserSessionModel userSession, UriInfo uriInfo, RealmModel realm) {
- if (getConfig().getLogoutUrl() == null || getConfig().getLogoutUrl().trim().equals("")) return null;
+ public void backchannelLogout(UserSessionModel userSession, UriInfo uriInfo, RealmModel realm) {
+ if (getConfig().getLogoutUrl() == null || getConfig().getLogoutUrl().trim().equals("") || !getConfig().isBackchannelSupported()) return;
+ String idToken = userSession.getNote(FEDERATED_ID_TOKEN);
+ if (idToken == null) return;
+ backchannelLogout(userSession, idToken);
+ }
+
+ protected void backchannelLogout(UserSessionModel userSession, String idToken) {
String sessionId = userSession.getId();
UriBuilder logoutUri = UriBuilder.fromUri(getConfig().getLogoutUrl())
- .queryParam("state", sessionId);
+ .queryParam("state", sessionId);
+ logoutUri.queryParam("id_token_hint", idToken);
+ String url = logoutUri.build().toString();
+ try {
+ int status = JsonSimpleHttp.doGet(url).asStatus();
+ boolean success = status >=200 && status < 400;
+ if (!success) {
+ logger.warn("Failed backchannel broker logout to: " + url);
+ }
+ } catch (Exception e) {
+ logger.warn("Failed backchannel broker logout to: " + url, e);
+ }
+ }
+
+
+ @Override
+ public Response keycloakInitiatedBrowserLogout(UserSessionModel userSession, UriInfo uriInfo, RealmModel realm) {
+ if (getConfig().getLogoutUrl() == null || getConfig().getLogoutUrl().trim().equals("")) return null;
String idToken = userSession.getNote(FEDERATED_ID_TOKEN);
- if (idToken != null) logoutUri.queryParam("id_token_hint", idToken);
- String redirect = RealmsResource.brokerUrl(uriInfo)
- .path(IdentityBrokerService.class, "getEndpoint")
- .path(OIDCEndpoint.class, "logoutResponse")
- .build(realm.getName(), getConfig().getAlias()).toString();
- logoutUri.queryParam("post_logout_redirect_uri", redirect);
- Response response = Response.status(302).location(logoutUri.build()).build();
- return response;
+ if (idToken != null && getConfig().isBackchannelSupported()) {
+ backchannelLogout(userSession, idToken);
+ return null;
+ } else {
+ String sessionId = userSession.getId();
+ UriBuilder logoutUri = UriBuilder.fromUri(getConfig().getLogoutUrl())
+ .queryParam("state", sessionId);
+ if (idToken != null) logoutUri.queryParam("id_token_hint", idToken);
+ String redirect = RealmsResource.brokerUrl(uriInfo)
+ .path(IdentityBrokerService.class, "getEndpoint")
+ .path(OIDCEndpoint.class, "logoutResponse")
+ .build(realm.getName(), getConfig().getAlias()).toString();
+ logoutUri.queryParam("post_logout_redirect_uri", redirect);
+ Response response = Response.status(302).location(logoutUri.build()).build();
+ return response;
+ }
}
@Override
@@ -184,9 +216,9 @@ public class OIDCIdentityProvider extends AbstractOAuth2IdentityProvider<OIDCIde
String email = (String)idToken.getOtherClaims().get(IDToken.EMAIL);
if (getConfig().getUserInfoUrl() != null && (id == null || name == null || preferredUsername == null || email == null) ) {
- JsonNode userInfo = SimpleHttp.doGet(getConfig().getUserInfoUrl())
- .header("Authorization", "Bearer " + accessToken)
- .asJson();
+ SimpleHttp request = JsonSimpleHttp.doGet(getConfig().getUserInfoUrl())
+ .header("Authorization", "Bearer " + accessToken);
+ JsonNode userInfo = JsonSimpleHttp.asJson(request);
id = getJsonProperty(userInfo, "sub");
name = getJsonProperty(userInfo, "name");
diff --git a/broker/oidc/src/main/java/org/keycloak/broker/oidc/OIDCIdentityProviderConfig.java b/broker/oidc/src/main/java/org/keycloak/broker/oidc/OIDCIdentityProviderConfig.java
index ce89bfa..cc40cdb 100755
--- a/broker/oidc/src/main/java/org/keycloak/broker/oidc/OIDCIdentityProviderConfig.java
+++ b/broker/oidc/src/main/java/org/keycloak/broker/oidc/OIDCIdentityProviderConfig.java
@@ -70,6 +70,14 @@ public class OIDCIdentityProviderConfig extends OAuth2IdentityProviderConfig {
getConfig().put("validateSignature", String.valueOf(validateSignature));
}
+ public boolean isBackchannelSupported() {
+ return Boolean.valueOf(getConfig().get("backchannelSupported"));
+ }
+
+ public void setBackchannelSupported(boolean backchannel) {
+ getConfig().put("backchannelSupported", String.valueOf(backchannel));
+ }
+
diff --git a/broker/oidc/src/main/java/org/keycloak/broker/oidc/OIDCIdentityProviderFactory.java b/broker/oidc/src/main/java/org/keycloak/broker/oidc/OIDCIdentityProviderFactory.java
index 6c57274..ca0c1bb 100755
--- a/broker/oidc/src/main/java/org/keycloak/broker/oidc/OIDCIdentityProviderFactory.java
+++ b/broker/oidc/src/main/java/org/keycloak/broker/oidc/OIDCIdentityProviderFactory.java
@@ -17,11 +17,10 @@
*/
package org.keycloak.broker.oidc;
-import org.keycloak.broker.oidc.util.SimpleHttp;
+import org.keycloak.broker.provider.util.SimpleHttp;
import org.keycloak.broker.provider.AbstractIdentityProviderFactory;
import org.keycloak.jose.jwk.JWK;
import org.keycloak.jose.jwk.JWKParser;
-import org.keycloak.jose.jws.Algorithm;
import org.keycloak.models.IdentityProviderModel;
import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.protocol.oidc.representations.JSONWebKeySet;
diff --git a/broker/oidc/src/main/java/org/keycloak/broker/oidc/util/JsonSimpleHttp.java b/broker/oidc/src/main/java/org/keycloak/broker/oidc/util/JsonSimpleHttp.java
new file mode 100755
index 0000000..6f63584
--- /dev/null
+++ b/broker/oidc/src/main/java/org/keycloak/broker/oidc/util/JsonSimpleHttp.java
@@ -0,0 +1,32 @@
+package org.keycloak.broker.oidc.util;
+
+import org.codehaus.jackson.JsonNode;
+import org.codehaus.jackson.map.ObjectMapper;
+import org.keycloak.broker.provider.util.SimpleHttp;
+
+import java.io.IOException;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class JsonSimpleHttp extends SimpleHttp {
+ public JsonSimpleHttp(String url, String method) {
+ super(url, method);
+ }
+
+ public static JsonSimpleHttp doGet(String url) {
+ return new JsonSimpleHttp(url, "GET");
+ }
+
+ public static JsonSimpleHttp doPost(String url) {
+ return new JsonSimpleHttp(url, "POST");
+ }
+
+ private static ObjectMapper mapper = new ObjectMapper();
+
+ public static JsonNode asJson(SimpleHttp request) throws IOException {
+ return mapper.readTree(request.asString());
+ }
+
+}
diff --git a/broker/saml/src/main/java/org/keycloak/broker/saml/SAMLEndpoint.java b/broker/saml/src/main/java/org/keycloak/broker/saml/SAMLEndpoint.java
index b3efc97..d2d32eb 100755
--- a/broker/saml/src/main/java/org/keycloak/broker/saml/SAMLEndpoint.java
+++ b/broker/saml/src/main/java/org/keycloak/broker/saml/SAMLEndpoint.java
@@ -218,7 +218,7 @@ public class SAMLEndpoint {
List<UserSessionModel> userSessions = session.sessions().getUserSessionByBrokerUserId(realm, brokerUserId);
for (UserSessionModel userSession : userSessions) {
try {
- AuthenticationManager.backchannelLogout(session, realm, userSession, uriInfo, clientConnection, headers);
+ AuthenticationManager.backchannelLogout(session, realm, userSession, uriInfo, clientConnection, headers, false);
} catch (Exception e) {
logger.warn("failed to do backchannel logout for userSession", e);
}
@@ -230,7 +230,7 @@ public class SAMLEndpoint {
UserSessionModel userSession = session.sessions().getUserSessionByBrokerSessionId(realm, brokerSessionId);
if (userSession != null) {
try {
- AuthenticationManager.backchannelLogout(session, realm, userSession, uriInfo, clientConnection, headers);
+ AuthenticationManager.backchannelLogout(session, realm, userSession, uriInfo, clientConnection, headers, false);
} catch (Exception e) {
logger.warn("failed to do backchannel logout for userSession", e);
}
diff --git a/broker/saml/src/main/java/org/keycloak/broker/saml/SAMLIdentityProvider.java b/broker/saml/src/main/java/org/keycloak/broker/saml/SAMLIdentityProvider.java
index 98fd6ef..4517a94 100755
--- a/broker/saml/src/main/java/org/keycloak/broker/saml/SAMLIdentityProvider.java
+++ b/broker/saml/src/main/java/org/keycloak/broker/saml/SAMLIdentityProvider.java
@@ -17,10 +17,12 @@
*/
package org.keycloak.broker.saml;
+import org.jboss.logging.Logger;
import org.keycloak.broker.provider.AbstractIdentityProvider;
import org.keycloak.broker.provider.AuthenticationRequest;
import org.keycloak.broker.provider.BrokeredIdentityContext;
import org.keycloak.broker.provider.IdentityBrokerException;
+import org.keycloak.broker.provider.util.SimpleHttp;
import org.keycloak.dom.saml.v2.assertion.AssertionType;
import org.keycloak.dom.saml.v2.assertion.AuthnStatementType;
import org.keycloak.dom.saml.v2.assertion.NameIDType;
@@ -34,12 +36,17 @@ import org.keycloak.models.UserSessionModel;
import org.keycloak.protocol.saml.SAML2AuthnRequestBuilder;
import org.keycloak.protocol.saml.SAML2LogoutRequestBuilder;
import org.keycloak.protocol.saml.SAML2NameIDPolicyBuilder;
+import org.keycloak.saml.common.constants.GeneralConstants;
import org.keycloak.saml.common.constants.JBossSAMLURIConstants;
+import org.keycloak.saml.common.exceptions.ConfigurationException;
+import org.keycloak.saml.common.exceptions.ParsingException;
+import org.keycloak.saml.common.exceptions.ProcessingException;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriBuilder;
import javax.ws.rs.core.UriInfo;
+import java.io.IOException;
import java.security.KeyPair;
import java.security.PrivateKey;
import java.security.PublicKey;
@@ -48,6 +55,7 @@ import java.security.PublicKey;
* @author Pedro Igor
*/
public class SAMLIdentityProvider extends AbstractIdentityProvider<SAMLIdentityProviderConfig> {
+ protected static final Logger logger = Logger.getLogger(SAMLIdentityProvider.class);
public SAMLIdentityProvider(SAMLIdentityProviderConfig config) {
super(config);
}
@@ -141,25 +149,56 @@ public class SAMLIdentityProvider extends AbstractIdentityProvider<SAMLIdentityP
}
@Override
+ public void backchannelLogout(UserSessionModel userSession, UriInfo uriInfo, RealmModel realm) {
+ String singleLogoutServiceUrl = getConfig().getSingleLogoutServiceUrl();
+ if (singleLogoutServiceUrl == null || singleLogoutServiceUrl.trim().equals("") || !getConfig().isBackchannelSupported()) return;
+ SAML2LogoutRequestBuilder logoutBuilder = buildLogoutRequest(userSession, uriInfo, realm, singleLogoutServiceUrl);
+ try {
+ int status = SimpleHttp.doPost(singleLogoutServiceUrl)
+ .param(GeneralConstants.SAML_REQUEST_KEY, logoutBuilder.postBinding().encoded())
+ .param(GeneralConstants.RELAY_STATE, userSession.getId()).asStatus();
+ boolean success = status >=200 && status < 400;
+ if (!success) {
+ logger.warn("Failed saml backchannel broker logout to: " + singleLogoutServiceUrl);
+ }
+ } catch (Exception e) {
+ logger.warn("Failed saml backchannel broker logout to: " + singleLogoutServiceUrl, e);
+ }
+
+ }
+
+ @Override
public Response keycloakInitiatedBrowserLogout(UserSessionModel userSession, UriInfo uriInfo, RealmModel realm) {
- if (getConfig().getSingleLogoutServiceUrl() == null || getConfig().getSingleLogoutServiceUrl().trim().equals("")) return null;
+ String singleLogoutServiceUrl = getConfig().getSingleLogoutServiceUrl();
+ if (singleLogoutServiceUrl == null || singleLogoutServiceUrl.trim().equals("")) return null;
+
+ if (getConfig().isBackchannelSupported()) {
+ backchannelLogout(userSession, uriInfo, realm);
+ return null;
+ } else {
+ try {
+ SAML2LogoutRequestBuilder logoutBuilder = buildLogoutRequest(userSession, uriInfo, realm, singleLogoutServiceUrl);
+ return logoutBuilder.postBinding().request();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ }
+ protected SAML2LogoutRequestBuilder buildLogoutRequest(UserSessionModel userSession, UriInfo uriInfo, RealmModel realm, String singleLogoutServiceUrl) {
SAML2LogoutRequestBuilder logoutBuilder = new SAML2LogoutRequestBuilder()
.assertionExpiration(realm.getAccessCodeLifespan())
.issuer(getEntityId(uriInfo, realm))
.sessionIndex(userSession.getNote(SAMLEndpoint.SAML_FEDERATED_SESSION_INDEX))
.userPrincipal(userSession.getNote(SAMLEndpoint.SAML_FEDERATED_SUBJECT), userSession.getNote(SAMLEndpoint.SAML_FEDERATED_SUBJECT_NAMEFORMAT))
- .destination(getConfig().getSingleLogoutServiceUrl());
+ .destination(singleLogoutServiceUrl)
+ .relayState(userSession.getId());
if (getConfig().isWantAuthnRequestsSigned()) {
logoutBuilder.signWith(realm.getPrivateKey(), realm.getPublicKey(), realm.getCertificate())
.signDocument();
}
- try {
- return logoutBuilder.relayState(userSession.getId()).postBinding().request();
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
-
+ return logoutBuilder;
}
@Override
diff --git a/broker/saml/src/main/java/org/keycloak/broker/saml/SAMLIdentityProviderConfig.java b/broker/saml/src/main/java/org/keycloak/broker/saml/SAMLIdentityProviderConfig.java
index 10ef464..ad11be3 100755
--- a/broker/saml/src/main/java/org/keycloak/broker/saml/SAMLIdentityProviderConfig.java
+++ b/broker/saml/src/main/java/org/keycloak/broker/saml/SAMLIdentityProviderConfig.java
@@ -110,4 +110,13 @@ public class SAMLIdentityProviderConfig extends IdentityProviderModel {
public void setPostBindingResponse(boolean postBindingResponse) {
getConfig().put("postBindingResponse", String.valueOf(postBindingResponse));
}
+
+ public boolean isBackchannelSupported() {
+ return Boolean.valueOf(getConfig().get("backchannelSupported"));
+ }
+
+ public void setBackchannelSupported(boolean backchannel) {
+ getConfig().put("backchannelSupported", String.valueOf(backchannel));
+ }
+
}
diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider-oidc.html b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider-oidc.html
index 6ae4a81..9d23164 100755
--- a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider-oidc.html
+++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider-oidc.html
@@ -42,7 +42,7 @@
<span tooltip-placement="right" tooltip="Indicates if this provider should be tried by default for authentication even before displaying login screen" class="fa fa-info-circle"></span>
</div>
<div class="form-group">
- <label class="col-sm-2 control-label" for="enabled">Store Tokens</label>
+ <label class="col-sm-2 control-label" for="storeToken">Store Tokens</label>
<div class="col-sm-4">
<input ng-model="identityProvider.storeToken" id="storeToken" onoffswitch />
</div>
@@ -93,6 +93,13 @@
</div>
<span tooltip-placement="right" tooltip="End session endpoint to use to logout user from external IDP." class="fa fa-info-circle"></span>
</div>
+ <div class="form-group">
+ <label class="col-sm-2 control-label" for="backchannelSupported">Backchannel Logout</label>
+ <div class="col-sm-4">
+ <input ng-model="identityProvider.config.backchannelSupported" id="backchannelSupported" value="'true'" onoffswitchvalue />
+ </div>
+ <span tooltip-placement="right" tooltip="Does the external IDP support backchannel logout?" class="fa fa-info-circle"></span>
+ </div>
<div class="form-group clearfix">
<label class="col-sm-2 control-label" for="userInfoUrl">User Info Url</label>
<div class="col-sm-4">
diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider-saml.html b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider-saml.html
index 6746d0a..05f4c63 100755
--- a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider-saml.html
+++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider-saml.html
@@ -42,7 +42,7 @@
<span tooltip-placement="right" tooltip="Indicates if this provider should be tried by default for authentication even before displaying login screen" class="fa fa-info-circle"></span>
</div>
<div class="form-group">
- <label class="col-sm-2 control-label" for="enabled">Store Tokens</label>
+ <label class="col-sm-2 control-label" for="storeToken">Store Tokens</label>
<div class="col-sm-4">
<input ng-model="identityProvider.storeToken" id="storeToken" onoffswitch />
</div>
@@ -87,6 +87,13 @@
</div>
<span tooltip-placement="right" tooltip="The Url that must be used to send logout requests." class="fa fa-info-circle"></span>
</div>
+ <div class="form-group">
+ <label class="col-sm-2 control-label" for="backchannelSupported">Backchannel Logout</label>
+ <div class="col-sm-4">
+ <input ng-model="identityProvider.config.backchannelSupported" id="backchannelSupported" value="'true'" onoffswitchvalue />
+ </div>
+ <span tooltip-placement="right" tooltip="Does the external IDP support backchannel logout?" class="fa fa-info-circle"></span>
+ </div>
<div class="form-group clearfix">
<label class="col-sm-2 control-label" for="nameIDPolicyFormat">NameID Policy Format</label>
<div class="col-sm-4">
diff --git a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SAML2BindingBuilder.java b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SAML2BindingBuilder.java
index 8143d15..7fe2fb3 100755
--- a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SAML2BindingBuilder.java
+++ b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SAML2BindingBuilder.java
@@ -39,6 +39,7 @@ import static org.keycloak.saml.common.util.StringUtil.isNotNull;
*/
public class SAML2BindingBuilder<T extends SAML2BindingBuilder> {
protected static final Logger logger = Logger.getLogger(SAML2BindingBuilder.class);
+ public static final String RELAY_STATE = "RelayState";
protected KeyPair signingKeyPair;
protected X509Certificate signingCertificate;
@@ -328,7 +329,7 @@ public class SAML2BindingBuilder<T extends SAML2BindingBuilder> {
builder.append("<INPUT TYPE=\"HIDDEN\" NAME=\"" + key + "\"" + " VALUE=\"" + samlResponse + "\"/>");
if (isNotNull(relayState)) {
- builder.append("<INPUT TYPE=\"HIDDEN\" NAME=\"RelayState\" " + "VALUE=\"" + escapeAttribute(relayState) + "\"/>");
+ builder.append("<INPUT TYPE=\"HIDDEN\" NAME=\"" + RELAY_STATE + "\" " + "VALUE=\"" + escapeAttribute(relayState) + "\"/>");
}
builder.append("<NOSCRIPT>");
@@ -355,7 +356,7 @@ public class SAML2BindingBuilder<T extends SAML2BindingBuilder> {
.replaceQuery(null)
.queryParam(samlParameterName, base64Encoded(document));
if (relayState != null) {
- builder.queryParam("RelayState", relayState);
+ builder.queryParam(RELAY_STATE, relayState);
}
if (sign) {
diff --git a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlProtocol.java b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlProtocol.java
index 315e685..f650b64 100755
--- a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlProtocol.java
+++ b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlProtocol.java
@@ -161,7 +161,7 @@ public class SamlProtocol implements LoginProtocol {
return SamlProtocol.SAML_POST_BINDING.equals(clientSession.getNote(SamlProtocol.SAML_BINDING)) || forcePostBinding(client);
}
- protected boolean isLogoutPostBindingForInitiator(UserSessionModel session) {
+ public static boolean isLogoutPostBindingForInitiator(UserSessionModel session) {
String note = session.getNote(SamlProtocol.SAML_LOGOUT_BINDING);
return SamlProtocol.SAML_POST_BINDING.equals(note);
}
diff --git a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlService.java b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlService.java
index ff936e5..d11ffb0 100755
--- a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlService.java
+++ b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlService.java
@@ -6,6 +6,12 @@ import org.jboss.resteasy.spi.HttpRequest;
import org.jboss.resteasy.spi.HttpResponse;
import org.keycloak.ClientConnection;
import org.keycloak.VerificationException;
+import org.keycloak.dom.saml.v2.SAML2Object;
+import org.keycloak.dom.saml.v2.protocol.AuthnRequestType;
+import org.keycloak.dom.saml.v2.protocol.LogoutRequestType;
+import org.keycloak.dom.saml.v2.protocol.NameIDPolicyType;
+import org.keycloak.dom.saml.v2.protocol.RequestAbstractType;
+import org.keycloak.dom.saml.v2.protocol.StatusResponseType;
import org.keycloak.events.Details;
import org.keycloak.events.Errors;
import org.keycloak.events.EventBuilder;
@@ -18,22 +24,18 @@ import org.keycloak.models.RealmModel;
import org.keycloak.models.UserSessionModel;
import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.protocol.oidc.utils.RedirectUtils;
+import org.keycloak.saml.common.constants.GeneralConstants;
+import org.keycloak.saml.common.constants.JBossSAMLURIConstants;
+import org.keycloak.saml.common.exceptions.ConfigurationException;
+import org.keycloak.saml.common.exceptions.ProcessingException;
+import org.keycloak.saml.processing.core.saml.v2.common.SAMLDocumentHolder;
+import org.keycloak.services.ErrorPage;
import org.keycloak.services.managers.AuthenticationManager;
import org.keycloak.services.managers.ClientSessionCode;
import org.keycloak.services.managers.HttpAuthenticationManager;
import org.keycloak.services.messages.Messages;
import org.keycloak.services.resources.RealmsResource;
-import org.keycloak.services.ErrorPage;
import org.keycloak.util.StreamUtil;
-import org.keycloak.saml.common.constants.GeneralConstants;
-import org.keycloak.saml.common.constants.JBossSAMLURIConstants;
-import org.keycloak.saml.processing.core.saml.v2.common.SAMLDocumentHolder;
-import org.keycloak.dom.saml.v2.SAML2Object;
-import org.keycloak.dom.saml.v2.protocol.AuthnRequestType;
-import org.keycloak.dom.saml.v2.protocol.LogoutRequestType;
-import org.keycloak.dom.saml.v2.protocol.NameIDPolicyType;
-import org.keycloak.dom.saml.v2.protocol.RequestAbstractType;
-import org.keycloak.dom.saml.v2.protocol.StatusResponseType;
import javax.ws.rs.Consumes;
import javax.ws.rs.FormParam;
@@ -51,6 +53,7 @@ import javax.ws.rs.core.SecurityContext;
import javax.ws.rs.core.UriBuilder;
import javax.ws.rs.core.UriInfo;
import javax.ws.rs.ext.Providers;
+import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.security.PublicKey;
@@ -122,7 +125,7 @@ public class SamlService {
protected Response handleSamlResponse(String samlResponse, String relayState) {
event.event(EventType.LOGOUT);
SAMLDocumentHolder holder = extractResponseDocument(samlResponse);
- StatusResponseType statusResponse = (StatusResponseType)holder.getSamlObject();
+ StatusResponseType statusResponse = (StatusResponseType) holder.getSamlObject();
// validate destination
if (!uriInfo.getAbsolutePath().toString().equals(statusResponse.getDestination())) {
event.error(Errors.INVALID_SAML_LOGOUT_RESPONSE);
@@ -162,7 +165,7 @@ public class SamlService {
SAML2Object samlObject = documentHolder.getSamlObject();
- RequestAbstractType requestAbstractType = (RequestAbstractType)samlObject;
+ RequestAbstractType requestAbstractType = (RequestAbstractType) samlObject;
String issuer = requestAbstractType.getIssuer().getValue();
ClientModel client = realm.getClientByClientId(issuer);
@@ -177,7 +180,7 @@ public class SamlService {
event.error(Errors.CLIENT_DISABLED);
return ErrorPage.error(session, Messages.LOGIN_REQUESTER_NOT_ENABLED);
}
- if ((client instanceof ClientModel) && ((ClientModel)client).isBearerOnly()) {
+ if ((client instanceof ClientModel) && ((ClientModel) client).isBearerOnly()) {
event.event(EventType.LOGIN);
event.error(Errors.NOT_ALLOWED);
return ErrorPage.error(session, Messages.BEARER_ONLY);
@@ -221,6 +224,7 @@ public class SamlService {
protected abstract void verifySignature(SAMLDocumentHolder documentHolder, ClientModel client) throws VerificationException;
protected abstract SAMLDocumentHolder extractRequestDocument(String samlRequest);
+
protected abstract SAMLDocumentHolder extractResponseDocument(String response);
protected Response loginRequest(String relayState, AuthnRequestType requestAbstractType, ClientModel client) {
@@ -231,7 +235,8 @@ public class SamlService {
return ErrorPage.error(session, Messages.INVALID_REQUEST);
}
String bindingType = getBindingType(requestAbstractType);
- if ("true".equals(client.getAttribute(SamlProtocol.SAML_FORCE_POST_BINDING))) bindingType = SamlProtocol.SAML_POST_BINDING;
+ if ("true".equals(client.getAttribute(SamlProtocol.SAML_FORCE_POST_BINDING)))
+ bindingType = SamlProtocol.SAML_POST_BINDING;
String redirect = null;
URI redirectUri = requestAbstractType.getAssertionConsumerServiceURL();
if (redirectUri != null && !"null".equals(redirectUri)) { // "null" is for testing purposes
@@ -243,7 +248,7 @@ public class SamlService {
redirect = client.getAttribute(SamlProtocol.SAML_ASSERTION_CONSUMER_URL_REDIRECT_ATTRIBUTE);
}
if (redirect == null && client instanceof ClientModel) {
- redirect = ((ClientModel)client).getManagementUrl();
+ redirect = ((ClientModel) client).getManagementUrl();
}
}
@@ -265,10 +270,10 @@ public class SamlService {
// Handle NameIDPolicy from SP
NameIDPolicyType nameIdPolicy = requestAbstractType.getNameIDPolicy();
- if(nameIdPolicy != null && !SamlProtocol.forceNameIdFormat(client)) {
+ if (nameIdPolicy != null && !SamlProtocol.forceNameIdFormat(client)) {
String nameIdFormat = nameIdPolicy.getFormat().toString();
// TODO: Handle AllowCreate too, relevant for persistent NameID.
- if(isSupportedNameIdFormat(nameIdFormat)) {
+ if (isSupportedNameIdFormat(nameIdFormat)) {
clientSession.setNote(GeneralConstants.NAMEID_FORMAT, nameIdFormat);
} else {
event.error(Errors.INVALID_SAML_AUTHN_REQUEST);
@@ -344,7 +349,8 @@ public class SamlService {
AuthenticationManager.AuthResult authResult = authManager.authenticateIdentityCookie(session, realm, uriInfo, clientConnection, headers, false);
if (authResult != null) {
String logoutBinding = getBindingType();
- if ("true".equals(client.getAttribute(SamlProtocol.SAML_FORCE_POST_BINDING))) logoutBinding = SamlProtocol.SAML_POST_BINDING;
+ if ("true".equals(client.getAttribute(SamlProtocol.SAML_FORCE_POST_BINDING)))
+ logoutBinding = SamlProtocol.SAML_POST_BINDING;
String bindingUri = SamlProtocol.getLogoutServiceUrl(uriInfo, client, logoutBinding);
UserSessionModel userSession = authResult.getSession();
userSession.setNote(SamlProtocol.SAML_LOGOUT_BINDING_URI, bindingUri);
@@ -364,33 +370,51 @@ public class SamlService {
}
logger.debug("browser Logout");
return authManager.browserLogout(session, realm, userSession, uriInfo, clientConnection, headers);
- }
-
+ } else if (logoutRequest.getSessionIndex() != null) {
+ for (String sessionIndex : logoutRequest.getSessionIndex()) {
+ ClientSessionModel clientSession = session.sessions().getClientSession(realm, sessionIndex);
+ if (clientSession == null) continue;
+ if (clientSession.getClient().getClientId().equals(client.getClientId())) {
+ // remove requesting client from logout
+ clientSession.setAction(ClientSessionModel.Action.LOGGED_OUT);
+ }
+ UserSessionModel userSession = clientSession.getUserSession();
+ try {
+ authManager.backchannelLogout(session, realm, userSession, uriInfo, clientConnection, headers, true);
+ } catch (Exception e) {
+ logger.warn("Failure with backchannel logout", e);
+ }
- String redirectUri = null;
+ }
- if (client instanceof ClientModel) {
- redirectUri = ((ClientModel)client).getBaseUrl();
}
- if (redirectUri != null) {
- redirectUri = RedirectUtils.verifyRedirectUri(uriInfo, redirectUri, realm, client);
- if (redirectUri == null) {
- return ErrorPage.error(session, Messages.INVALID_REDIRECT_URI);
- }
+ // default
+
+ String logoutBinding = getBindingType();
+ String logoutBindingUri = SamlProtocol.getLogoutServiceUrl(uriInfo, client, logoutBinding);
+ String logoutRelayState = relayState;
+ SAML2LogoutResponseBuilder builder = new SAML2LogoutResponseBuilder();
+ builder.logoutRequestID(logoutRequest.getID());
+ builder.destination(logoutBindingUri);
+ builder.issuer(RealmsResource.realmBaseUrl(uriInfo).build(realm.getName()).toString());
+ builder.relayState(logoutRelayState);
+ if (SamlProtocol.requiresRealmSignature(client)) {
+ SignatureAlgorithm algorithm = SamlProtocol.getSignatureAlgorithm(client);
+ builder.signatureAlgorithm(algorithm)
+ .signWith(realm.getPrivateKey(), realm.getPublicKey(), realm.getCertificate())
+ .signDocument();
+
}
- if (redirectUri != null) {
- return Response.status(302).location(UriBuilder.fromUri(redirectUri).build()).build();
- } else {
- return Response.ok().build();
+ try {
+ if (SamlProtocol.SAML_POST_BINDING.equals(logoutBinding)) {
+ return builder.postBinding().response(logoutBindingUri);
+ } else {
+ return builder.redirectBinding().response(logoutBindingUri);
+ }
+ } catch (Exception e) {
+ throw new RuntimeException(e);
}
-
- }
-
- private Response logout(UserSessionModel userSession) {
- Response response = authManager.browserLogout(session, realm, userSession, uriInfo, clientConnection, headers);
- if (response == null) event.user(userSession.getUser()).session(userSession).success();
- return response;
}
private boolean checkSsl() {
@@ -414,6 +438,7 @@ public class SamlService {
protected SAMLDocumentHolder extractRequestDocument(String samlRequest) {
return SAMLRequestParser.parseRequestPostBinding(samlRequest);
}
+
@Override
protected SAMLDocumentHolder extractResponseDocument(String response) {
return SAMLRequestParser.parseResponsePostBinding(response);
@@ -446,7 +471,6 @@ public class SamlService {
}
-
@Override
protected SAMLDocumentHolder extractRequestDocument(String samlRequest) {
return SAMLRequestParser.parseRequestRedirectBinding(samlRequest);
@@ -478,7 +502,7 @@ public class SamlService {
@GET
public Response redirectBinding(@QueryParam(GeneralConstants.SAML_REQUEST_KEY) String samlRequest,
@QueryParam(GeneralConstants.SAML_RESPONSE_KEY) String samlResponse,
- @QueryParam(GeneralConstants.RELAY_STATE) String relayState) {
+ @QueryParam(GeneralConstants.RELAY_STATE) String relayState) {
logger.debug("SAML GET");
return new RedirectBindingProtocol().execute(samlRequest, samlResponse, relayState);
}
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/LogoutEndpoint.java b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/LogoutEndpoint.java
index 31cdca3..efc2f46 100755
--- a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/LogoutEndpoint.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/LogoutEndpoint.java
@@ -126,7 +126,7 @@ public class LogoutEndpoint {
return AuthenticationManager.browserLogout(session, realm, authResult.getSession(), uriInfo, clientConnection, headers);
} else if (userSession != null) { // non browser logout
event.event(EventType.LOGOUT);
- authManager.backchannelLogout(session, realm, userSession, uriInfo, clientConnection, headers);
+ authManager.backchannelLogout(session, realm, userSession, uriInfo, clientConnection, headers, true);
event.user(userSession.getUser()).session(userSession).success();
}
@@ -183,7 +183,7 @@ public class LogoutEndpoint {
}
private void logout(UserSessionModel userSession) {
- authManager.backchannelLogout(session, realm, userSession, uriInfo, clientConnection, headers);
+ authManager.backchannelLogout(session, realm, userSession, uriInfo, clientConnection, headers, true);
event.user(userSession.getUser()).session(userSession).success();
}
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/TokenManager.java b/services/src/main/java/org/keycloak/protocol/oidc/TokenManager.java
index f77fbdd..b728607 100755
--- a/services/src/main/java/org/keycloak/protocol/oidc/TokenManager.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/TokenManager.java
@@ -86,7 +86,7 @@ public class TokenManager {
UserSessionModel userSession = session.sessions().getUserSession(realm, oldToken.getSessionState());
if (!AuthenticationManager.isSessionValid(realm, userSession)) {
- AuthenticationManager.backchannelLogout(session, realm, userSession, uriInfo, connection, headers);
+ AuthenticationManager.backchannelLogout(session, realm, userSession, uriInfo, connection, headers, true);
throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "Session not active", "Session not active");
}
ClientSessionModel clientSession = null;
diff --git a/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java b/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java
index 6a96037..2bb4d8f 100755
--- a/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java
+++ b/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java
@@ -104,7 +104,20 @@ public class AuthenticationManager {
}
- public static void backchannelLogout(KeycloakSession session, RealmModel realm, UserSessionModel userSession, UriInfo uriInfo, ClientConnection connection, HttpHeaders headers) {
+ /**
+ * Do not logout broker
+ *
+ * @param session
+ * @param realm
+ * @param userSession
+ * @param uriInfo
+ * @param connection
+ * @param headers
+ */
+ public static void backchannelLogout(KeycloakSession session, RealmModel realm,
+ UserSessionModel userSession, UriInfo uriInfo,
+ ClientConnection connection, HttpHeaders headers,
+ boolean logoutBroker) {
if (userSession == null) return;
UserModel user = userSession.getUser();
userSession.setState(UserSessionModel.State.LOGGING_OUT);
@@ -115,6 +128,16 @@ public class AuthenticationManager {
for (ClientSessionModel clientSession : userSession.getClientSessions()) {
backchannelLogoutClientSession(session, realm, clientSession, userSession, uriInfo, headers);
}
+ if (logoutBroker) {
+ String brokerId = userSession.getNote(IdentityBrokerService.BROKER_PROVIDER_ID);
+ if (brokerId != null) {
+ IdentityProvider identityProvider = IdentityBrokerService.getIdentityProvider(session, realm, brokerId);
+ try {
+ identityProvider.backchannelLogout(userSession, uriInfo, realm);
+ } catch (Exception e) {
+ }
+ }
+ }
userSession.setState(UserSessionModel.State.LOGGED_OUT);
session.sessions().removeUserSession(realm, userSession);
}
@@ -131,8 +154,8 @@ public class AuthenticationManager {
protocol.backchannelLogout(userSession, clientSession);
clientSession.setAction(ClientSessionModel.Action.LOGGED_OUT);
}
- }
+ }
public static Response browserLogout(KeycloakSession session, RealmModel realm, UserSessionModel userSession, UriInfo uriInfo, ClientConnection connection, HttpHeaders headers) {
if (userSession == null) return null;
@@ -525,7 +548,7 @@ public class AuthenticationManager {
UserSessionModel userSession = session.sessions().getUserSession(realm, token.getSessionState());
if (!isSessionValid(realm, userSession)) {
- if (userSession != null) backchannelLogout(session, realm, userSession, uriInfo, connection, headers);
+ if (userSession != null) backchannelLogout(session, realm, userSession, uriInfo, connection, headers, true);
logger.debug("User session not active");
return null;
}
diff --git a/services/src/main/java/org/keycloak/services/resources/AccountService.java b/services/src/main/java/org/keycloak/services/resources/AccountService.java
index bc81f46..207c5b7 100755
--- a/services/src/main/java/org/keycloak/services/resources/AccountService.java
+++ b/services/src/main/java/org/keycloak/services/resources/AccountService.java
@@ -480,7 +480,7 @@ public class AccountService {
UserModel user = auth.getUser();
List<UserSessionModel> userSessions = session.sessions().getUserSessions(realm, user);
for (UserSessionModel userSession : userSessions) {
- AuthenticationManager.backchannelLogout(session, realm, userSession, uriInfo, clientConnection, headers);
+ AuthenticationManager.backchannelLogout(session, realm, userSession, uriInfo, clientConnection, headers, true);
}
UriBuilder builder = Urls.accountBase(uriInfo.getBaseUri()).path(AccountService.class, "sessionsPage");
@@ -675,7 +675,7 @@ public class AccountService {
List<UserSessionModel> sessions = session.sessions().getUserSessions(realm, user);
for (UserSessionModel s : sessions) {
if (!s.getId().equals(auth.getSession().getId())) {
- AuthenticationManager.backchannelLogout(session, realm, s, uriInfo, clientConnection, headers);
+ AuthenticationManager.backchannelLogout(session, realm, s, uriInfo, clientConnection, headers, true);
}
}
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java b/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java
index 6031c2e..129ee5e 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java
@@ -280,7 +280,7 @@ public class RealmAdminResource {
public void deleteSession(@PathParam("session") String sessionId) {
UserSessionModel userSession = session.sessions().getUserSession(realm, sessionId);
if (userSession == null) throw new NotFoundException("Sesssion not found");
- AuthenticationManager.backchannelLogout(session, realm, userSession, uriInfo, connection, headers);
+ AuthenticationManager.backchannelLogout(session, realm, userSession, uriInfo, connection, headers, true);
}
/**
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/UsersResource.java b/services/src/main/java/org/keycloak/services/resources/admin/UsersResource.java
index 20aeaa5..49abc1d 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/UsersResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/UsersResource.java
@@ -379,7 +379,7 @@ public class UsersResource {
List<UserSessionModel> userSessions = session.sessions().getUserSessions(realm, user);
for (UserSessionModel userSession : userSessions) {
- AuthenticationManager.backchannelLogout(session, realm, userSession, uriInfo, clientConnection, headers);
+ AuthenticationManager.backchannelLogout(session, realm, userSession, uriInfo, clientConnection, headers, true);
}
}
diff --git a/services/src/main/java/org/keycloak/services/resources/LoginActionsService.java b/services/src/main/java/org/keycloak/services/resources/LoginActionsService.java
index aeb3e2a..4704943 100755
--- a/services/src/main/java/org/keycloak/services/resources/LoginActionsService.java
+++ b/services/src/main/java/org/keycloak/services/resources/LoginActionsService.java
@@ -595,7 +595,7 @@ public class LoginActionsService {
}
if (!AuthenticationManager.isSessionValid(realm, userSession)) {
- AuthenticationManager.backchannelLogout(session, realm, userSession, uriInfo, clientConnection, headers);
+ AuthenticationManager.backchannelLogout(session, realm, userSession, uriInfo, clientConnection, headers, true);
event.error(Errors.INVALID_CODE);
return ErrorPage.error(session, Messages.SESSION_NOT_ACTIVE);
}
diff --git a/social/facebook/src/main/java/org/keycloak/social/facebook/FacebookIdentityProvider.java b/social/facebook/src/main/java/org/keycloak/social/facebook/FacebookIdentityProvider.java
index cc9364f..ffce087 100755
--- a/social/facebook/src/main/java/org/keycloak/social/facebook/FacebookIdentityProvider.java
+++ b/social/facebook/src/main/java/org/keycloak/social/facebook/FacebookIdentityProvider.java
@@ -3,7 +3,8 @@ package org.keycloak.social.facebook;
import org.codehaus.jackson.JsonNode;
import org.keycloak.broker.oidc.AbstractOAuth2IdentityProvider;
import org.keycloak.broker.oidc.OAuth2IdentityProviderConfig;
-import org.keycloak.broker.oidc.util.SimpleHttp;
+import org.keycloak.broker.oidc.util.JsonSimpleHttp;
+import org.keycloak.broker.provider.util.SimpleHttp;
import org.keycloak.broker.provider.BrokeredIdentityContext;
import org.keycloak.broker.provider.IdentityBrokerException;
import org.keycloak.social.SocialIdentityProvider;
@@ -27,7 +28,7 @@ public class FacebookIdentityProvider extends AbstractOAuth2IdentityProvider imp
protected BrokeredIdentityContext doGetFederatedIdentity(String accessToken) {
try {
- JsonNode profile = SimpleHttp.doGet(PROFILE_URL).header("Authorization", "Bearer " + accessToken).asJson();
+ JsonNode profile = JsonSimpleHttp.asJson(SimpleHttp.doGet(PROFILE_URL).header("Authorization", "Bearer " + accessToken));
String id = getJsonProperty(profile, "id");
diff --git a/social/github/src/main/java/org/keycloak/social/github/GitHubIdentityProvider.java b/social/github/src/main/java/org/keycloak/social/github/GitHubIdentityProvider.java
index ec56d15..d9db0e9 100755
--- a/social/github/src/main/java/org/keycloak/social/github/GitHubIdentityProvider.java
+++ b/social/github/src/main/java/org/keycloak/social/github/GitHubIdentityProvider.java
@@ -3,7 +3,8 @@ package org.keycloak.social.github;
import org.codehaus.jackson.JsonNode;
import org.keycloak.broker.oidc.AbstractOAuth2IdentityProvider;
import org.keycloak.broker.oidc.OAuth2IdentityProviderConfig;
-import org.keycloak.broker.oidc.util.SimpleHttp;
+import org.keycloak.broker.oidc.util.JsonSimpleHttp;
+import org.keycloak.broker.provider.util.SimpleHttp;
import org.keycloak.broker.provider.BrokeredIdentityContext;
import org.keycloak.broker.provider.IdentityBrokerException;
import org.keycloak.social.SocialIdentityProvider;
@@ -28,7 +29,7 @@ public class GitHubIdentityProvider extends AbstractOAuth2IdentityProvider imple
@Override
protected BrokeredIdentityContext doGetFederatedIdentity(String accessToken) {
try {
- JsonNode profile = SimpleHttp.doGet(PROFILE_URL).header("Authorization", "Bearer " + accessToken).asJson();
+ JsonNode profile = JsonSimpleHttp.asJson(SimpleHttp.doGet(PROFILE_URL).header("Authorization", "Bearer " + accessToken));
BrokeredIdentityContext user = new BrokeredIdentityContext(getJsonProperty(profile, "id"));
diff --git a/social/linkedin/src/main/java/org/keycloak/social/linkedin/LinkedInIdentityProvider.java b/social/linkedin/src/main/java/org/keycloak/social/linkedin/LinkedInIdentityProvider.java
index 911a55c..c031443 100755
--- a/social/linkedin/src/main/java/org/keycloak/social/linkedin/LinkedInIdentityProvider.java
+++ b/social/linkedin/src/main/java/org/keycloak/social/linkedin/LinkedInIdentityProvider.java
@@ -25,7 +25,8 @@ import org.codehaus.jackson.JsonNode;
import org.jboss.logging.Logger;
import org.keycloak.broker.oidc.AbstractOAuth2IdentityProvider;
import org.keycloak.broker.oidc.OAuth2IdentityProviderConfig;
-import org.keycloak.broker.oidc.util.SimpleHttp;
+import org.keycloak.broker.oidc.util.JsonSimpleHttp;
+import org.keycloak.broker.provider.util.SimpleHttp;
import org.keycloak.broker.provider.BrokeredIdentityContext;
import org.keycloak.broker.provider.IdentityBrokerException;
import org.keycloak.social.SocialIdentityProvider;
@@ -55,7 +56,7 @@ public class LinkedInIdentityProvider extends AbstractOAuth2IdentityProvider imp
protected BrokeredIdentityContext doGetFederatedIdentity(String accessToken) {
log.debug("doGetFederatedIdentity()");
try {
- JsonNode profile = SimpleHttp.doGet(PROFILE_URL).header("Authorization", "Bearer " + accessToken).asJson();
+ JsonNode profile = JsonSimpleHttp.asJson(SimpleHttp.doGet(PROFILE_URL).header("Authorization", "Bearer " + accessToken));
BrokeredIdentityContext user = new BrokeredIdentityContext(getJsonProperty(profile, "id"));
diff --git a/social/stackoverflow/src/main/java/org/keycloak/social/stackoverflow/StackoverflowIdentityProvider.java b/social/stackoverflow/src/main/java/org/keycloak/social/stackoverflow/StackoverflowIdentityProvider.java
index f834464..3e9cc8c 100755
--- a/social/stackoverflow/src/main/java/org/keycloak/social/stackoverflow/StackoverflowIdentityProvider.java
+++ b/social/stackoverflow/src/main/java/org/keycloak/social/stackoverflow/StackoverflowIdentityProvider.java
@@ -26,7 +26,8 @@ import java.util.HashMap;
import org.codehaus.jackson.JsonNode;
import org.jboss.logging.Logger;
import org.keycloak.broker.oidc.AbstractOAuth2IdentityProvider;
-import org.keycloak.broker.oidc.util.SimpleHttp;
+import org.keycloak.broker.oidc.util.JsonSimpleHttp;
+import org.keycloak.broker.provider.util.SimpleHttp;
import org.keycloak.broker.provider.BrokeredIdentityContext;
import org.keycloak.broker.provider.IdentityBrokerException;
import org.keycloak.social.SocialIdentityProvider;
@@ -64,7 +65,7 @@ public class StackoverflowIdentityProvider extends AbstractOAuth2IdentityProvide
if (log.isDebugEnabled()) {
log.debug("StackOverflow profile request to: " + URL);
}
- JsonNode profile = SimpleHttp.doGet(URL).asJson().get("items").get(0);
+ JsonNode profile = JsonSimpleHttp.asJson(SimpleHttp.doGet(URL)).get("items").get(0);
BrokeredIdentityContext user = new BrokeredIdentityContext(getJsonProperty(profile, "user_id"));
diff --git a/testsuite/integration/src/test/resources/broker-test/test-realm-with-broker.json b/testsuite/integration/src/test/resources/broker-test/test-realm-with-broker.json
index 50e45b9..009fda5 100755
--- a/testsuite/integration/src/test/resources/broker-test/test-realm-with-broker.json
+++ b/testsuite/integration/src/test/resources/broker-test/test-realm-with-broker.json
@@ -120,7 +120,8 @@
"forceAuthn": true,
"validateSignature": true,
"postBindingResponse": true,
- "postBindingAuthnRequest": true
+ "postBindingAuthnRequest": true,
+ "backchannelSupported": true
}
},
{
@@ -169,7 +170,8 @@
"tokenUrl": "http://localhost:8082/auth/realms/realm-with-oidc-identity-provider/protocol/openid-connect/token",
"userInfoUrl": "http://localhost:8082/auth/realms/realm-with-oidc-identity-provider/protocol/openid-connect/userinfo",
"logoutUrl": "http://localhost:8082/auth/realms/realm-with-oidc-identity-provider/tokens/logout",
- "defaultScope": "email profile"
+ "defaultScope": "email profile",
+ "backchannelSupported": "true"
}
}
],