KEYCLOAK-4504 New configuration option for SAML Broker:
* postBindingLogout: Indicates if POST or redirect should be used for the logout requests. This applies to both IdP-initiated logout, and Keycloak-initiated logout. If unset (for example when upgrading Keycloak), the setting is initially set to the same as postBindingResponse. The flag is also set when importing IdP metadata.
This commit is contained in:
parent
75909a0add
commit
8d82390843
7 changed files with 39 additions and 9 deletions
|
@ -303,7 +303,7 @@ public class SAMLEndpoint {
|
||||||
builder.issuer(issuerURL);
|
builder.issuer(issuerURL);
|
||||||
JaxrsSAML2BindingBuilder binding = new JaxrsSAML2BindingBuilder()
|
JaxrsSAML2BindingBuilder binding = new JaxrsSAML2BindingBuilder()
|
||||||
.relayState(relayState);
|
.relayState(relayState);
|
||||||
boolean postBinding = config.isPostBindingResponse();
|
boolean postBinding = config.isPostBindingLogout();
|
||||||
if (config.isWantAuthnRequestsSigned()) {
|
if (config.isWantAuthnRequestsSigned()) {
|
||||||
KeyManager.ActiveRsaKey keys = session.keys().getActiveRsaKey(realm);
|
KeyManager.ActiveRsaKey keys = session.keys().getActiveRsaKey(realm);
|
||||||
String keyName = config.getXmlSigKeyInfoKeyNameTransformer().getKeyName(keys.getKid(), keys.getCertificate());
|
String keyName = config.getXmlSigKeyInfoKeyNameTransformer().getKeyName(keys.getKid(), keys.getCertificate());
|
||||||
|
|
|
@ -184,12 +184,15 @@ public class SAMLIdentityProvider extends AbstractIdentityProvider<SAMLIdentityP
|
||||||
try {
|
try {
|
||||||
SAML2LogoutRequestBuilder logoutBuilder = buildLogoutRequest(userSession, uriInfo, realm, singleLogoutServiceUrl);
|
SAML2LogoutRequestBuilder logoutBuilder = buildLogoutRequest(userSession, uriInfo, realm, singleLogoutServiceUrl);
|
||||||
JaxrsSAML2BindingBuilder binding = buildLogoutBinding(session, userSession, realm);
|
JaxrsSAML2BindingBuilder binding = buildLogoutBinding(session, userSession, realm);
|
||||||
|
if (getConfig().isPostBindingLogout()) {
|
||||||
return binding.postBinding(logoutBuilder.buildDocument()).request(singleLogoutServiceUrl);
|
return binding.postBinding(logoutBuilder.buildDocument()).request(singleLogoutServiceUrl);
|
||||||
|
} else {
|
||||||
|
return binding.redirectBinding(logoutBuilder.buildDocument()).request(singleLogoutServiceUrl);
|
||||||
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected SAML2LogoutRequestBuilder buildLogoutRequest(UserSessionModel userSession, UriInfo uriInfo, RealmModel realm, String singleLogoutServiceUrl) {
|
protected SAML2LogoutRequestBuilder buildLogoutRequest(UserSessionModel userSession, UriInfo uriInfo, RealmModel realm, String singleLogoutServiceUrl) {
|
||||||
|
|
|
@ -161,6 +161,20 @@ public class SAMLIdentityProviderConfig extends IdentityProviderModel {
|
||||||
getConfig().put("postBindingResponse", String.valueOf(postBindingResponse));
|
getConfig().put("postBindingResponse", String.valueOf(postBindingResponse));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isPostBindingLogout() {
|
||||||
|
String postBindingLogout = getConfig().get("postBindingLogout");
|
||||||
|
if (postBindingLogout == null) {
|
||||||
|
// To maintain unchanged behavior when adding this field, we set the inital value to equal that
|
||||||
|
// of the binding for the response:
|
||||||
|
return isPostBindingResponse();
|
||||||
|
}
|
||||||
|
return Boolean.valueOf(postBindingLogout);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPostBindingLogout(boolean postBindingLogout) {
|
||||||
|
getConfig().put("postBindingLogout", String.valueOf(postBindingLogout));
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isBackchannelSupported() {
|
public boolean isBackchannelSupported() {
|
||||||
return Boolean.valueOf(getConfig().get("backchannelSupported"));
|
return Boolean.valueOf(getConfig().get("backchannelSupported"));
|
||||||
}
|
}
|
||||||
|
|
|
@ -84,11 +84,12 @@ public class SAMLIdentityProviderFactory extends AbstractIdentityProviderFactory
|
||||||
if (idpDescriptor != null) {
|
if (idpDescriptor != null) {
|
||||||
SAMLIdentityProviderConfig samlIdentityProviderConfig = new SAMLIdentityProviderConfig();
|
SAMLIdentityProviderConfig samlIdentityProviderConfig = new SAMLIdentityProviderConfig();
|
||||||
String singleSignOnServiceUrl = null;
|
String singleSignOnServiceUrl = null;
|
||||||
boolean postBinding = false;
|
boolean postBindingResponse = false;
|
||||||
|
boolean postBindingLogout = false;
|
||||||
for (EndpointType endpoint : idpDescriptor.getSingleSignOnService()) {
|
for (EndpointType endpoint : idpDescriptor.getSingleSignOnService()) {
|
||||||
if (endpoint.getBinding().toString().equals(JBossSAMLURIConstants.SAML_HTTP_POST_BINDING.get())) {
|
if (endpoint.getBinding().toString().equals(JBossSAMLURIConstants.SAML_HTTP_POST_BINDING.get())) {
|
||||||
singleSignOnServiceUrl = endpoint.getLocation().toString();
|
singleSignOnServiceUrl = endpoint.getLocation().toString();
|
||||||
postBinding = true;
|
postBindingResponse = true;
|
||||||
break;
|
break;
|
||||||
} else if (endpoint.getBinding().toString().equals(JBossSAMLURIConstants.SAML_HTTP_REDIRECT_BINDING.get())){
|
} else if (endpoint.getBinding().toString().equals(JBossSAMLURIConstants.SAML_HTTP_REDIRECT_BINDING.get())){
|
||||||
singleSignOnServiceUrl = endpoint.getLocation().toString();
|
singleSignOnServiceUrl = endpoint.getLocation().toString();
|
||||||
|
@ -96,10 +97,11 @@ public class SAMLIdentityProviderFactory extends AbstractIdentityProviderFactory
|
||||||
}
|
}
|
||||||
String singleLogoutServiceUrl = null;
|
String singleLogoutServiceUrl = null;
|
||||||
for (EndpointType endpoint : idpDescriptor.getSingleLogoutService()) {
|
for (EndpointType endpoint : idpDescriptor.getSingleLogoutService()) {
|
||||||
if (postBinding && endpoint.getBinding().toString().equals(JBossSAMLURIConstants.SAML_HTTP_POST_BINDING.get())) {
|
if (postBindingResponse && endpoint.getBinding().toString().equals(JBossSAMLURIConstants.SAML_HTTP_POST_BINDING.get())) {
|
||||||
singleLogoutServiceUrl = endpoint.getLocation().toString();
|
singleLogoutServiceUrl = endpoint.getLocation().toString();
|
||||||
|
postBindingLogout = true;
|
||||||
break;
|
break;
|
||||||
} else if (!postBinding && endpoint.getBinding().toString().equals(JBossSAMLURIConstants.SAML_HTTP_REDIRECT_BINDING.get())){
|
} else if (!postBindingResponse && endpoint.getBinding().toString().equals(JBossSAMLURIConstants.SAML_HTTP_REDIRECT_BINDING.get())){
|
||||||
singleLogoutServiceUrl = endpoint.getLocation().toString();
|
singleLogoutServiceUrl = endpoint.getLocation().toString();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -110,8 +112,9 @@ public class SAMLIdentityProviderFactory extends AbstractIdentityProviderFactory
|
||||||
samlIdentityProviderConfig.setWantAuthnRequestsSigned(idpDescriptor.isWantAuthnRequestsSigned());
|
samlIdentityProviderConfig.setWantAuthnRequestsSigned(idpDescriptor.isWantAuthnRequestsSigned());
|
||||||
samlIdentityProviderConfig.setAddExtensionsElementWithKeyInfo(false);
|
samlIdentityProviderConfig.setAddExtensionsElementWithKeyInfo(false);
|
||||||
samlIdentityProviderConfig.setValidateSignature(idpDescriptor.isWantAuthnRequestsSigned());
|
samlIdentityProviderConfig.setValidateSignature(idpDescriptor.isWantAuthnRequestsSigned());
|
||||||
samlIdentityProviderConfig.setPostBindingResponse(postBinding);
|
samlIdentityProviderConfig.setPostBindingResponse(postBindingResponse);
|
||||||
samlIdentityProviderConfig.setPostBindingAuthnRequest(postBinding);
|
samlIdentityProviderConfig.setPostBindingAuthnRequest(postBindingResponse);
|
||||||
|
samlIdentityProviderConfig.setPostBindingLogout(postBindingLogout);
|
||||||
|
|
||||||
List<KeyDescriptorType> keyDescriptor = idpDescriptor.getKeyDescriptor();
|
List<KeyDescriptorType> keyDescriptor = idpDescriptor.getKeyDescriptor();
|
||||||
String defaultCertificate = null;
|
String defaultCertificate = null;
|
||||||
|
|
|
@ -529,6 +529,7 @@ public class IdentityProviderTest extends AbstractAdminTest {
|
||||||
assertThat(config.keySet(), containsInAnyOrder(
|
assertThat(config.keySet(), containsInAnyOrder(
|
||||||
"validateSignature",
|
"validateSignature",
|
||||||
"singleLogoutServiceUrl",
|
"singleLogoutServiceUrl",
|
||||||
|
"postBindingLogout",
|
||||||
"postBindingResponse",
|
"postBindingResponse",
|
||||||
"postBindingAuthnRequest",
|
"postBindingAuthnRequest",
|
||||||
"singleSignOnServiceUrl",
|
"singleSignOnServiceUrl",
|
||||||
|
|
|
@ -523,6 +523,8 @@ http-post-binding-response=HTTP-POST Binding Response
|
||||||
http-post-binding-response.tooltip=Indicates whether to respond to requests using HTTP-POST binding. If false, HTTP-REDIRECT binding will be used.
|
http-post-binding-response.tooltip=Indicates whether to respond to requests using HTTP-POST binding. If false, HTTP-REDIRECT binding will be used.
|
||||||
http-post-binding-for-authn-request=HTTP-POST Binding for AuthnRequest
|
http-post-binding-for-authn-request=HTTP-POST Binding for AuthnRequest
|
||||||
http-post-binding-for-authn-request.tooltip=Indicates whether the AuthnRequest must be sent using HTTP-POST binding. If false, HTTP-REDIRECT binding will be used.
|
http-post-binding-for-authn-request.tooltip=Indicates whether the AuthnRequest must be sent using HTTP-POST binding. If false, HTTP-REDIRECT binding will be used.
|
||||||
|
http-post-binding-logout=HTTP-POST Binding Logout
|
||||||
|
http-post-binding-logout.tooltip=Indicates whether to respond to requests using HTTP-POST binding. If false, HTTP-REDIRECT binding will be used.
|
||||||
want-authn-requests-signed=Want AuthnRequests Signed
|
want-authn-requests-signed=Want AuthnRequests Signed
|
||||||
want-authn-requests-signed.tooltip=Indicates whether the identity provider expects signed a AuthnRequest.
|
want-authn-requests-signed.tooltip=Indicates whether the identity provider expects signed a AuthnRequest.
|
||||||
force-authentication=Force Authentication
|
force-authentication=Force Authentication
|
||||||
|
|
|
@ -142,6 +142,13 @@
|
||||||
</div>
|
</div>
|
||||||
<kc-tooltip>{{:: 'http-post-binding-for-authn-request.tooltip' | translate}}</kc-tooltip>
|
<kc-tooltip>{{:: 'http-post-binding-for-authn-request.tooltip' | translate}}</kc-tooltip>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-md-2 control-label" for="postBindingLogout">{{:: 'http-post-binding-logout' | translate}}</label>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<input ng-model="identityProvider.config.postBindingLogout" id="postBindingLogout" onoffswitchvalue on-text="{{:: 'onText' | translate}}" off-text="{{:: 'offText' | translate}}" />
|
||||||
|
</div>
|
||||||
|
<kc-tooltip>{{:: 'http-post-binding-logout.tooltip' | translate}}</kc-tooltip>
|
||||||
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="col-md-2 control-label" for="wantAuthnRequestsSigned">{{:: 'want-authn-requests-signed' | translate}}</label>
|
<label class="col-md-2 control-label" for="wantAuthnRequestsSigned">{{:: 'want-authn-requests-signed' | translate}}</label>
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
|
|
Loading…
Reference in a new issue