Skip to content

Commit

Permalink
Handle RelayState in preparing a SAMLAuthN Request (elastic#46534)
Browse files Browse the repository at this point in the history
This change allows for the caller of the `saml/prepare` API to pass
a `relay_state` parameter that will then be part of the redirect
URL in the response as the `RelayState` query parameter.

The SAML IdP is required to reflect back the value of that relay
state when sending a SAML Response. The caller of the APIs can
then, when receiving the SAML Response, read and consume the value
as it see fit.
  • Loading branch information
jkakavas committed Sep 25, 2019
1 parent 6f453aa commit 811a148
Show file tree
Hide file tree
Showing 6 changed files with 30 additions and 7 deletions.
4 changes: 2 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -179,8 +179,8 @@ task verifyVersions {
* after the backport of the backcompat code is complete.
*/

boolean bwc_tests_enabled = true
final String bwc_tests_disabled_issue = "" /* place a PR link here when committing bwc changes */
boolean bwc_tests_enabled = false
final String bwc_tests_disabled_issue = "https://github.com/elastic/elasticsearch/pull/46534" /* place a PR link here when committing bwc changes */
if (bwc_tests_enabled == false) {
if (bwc_tests_disabled_issue.isEmpty()) {
throw new GradleException("bwc_tests_disabled_issue must be set when bwc_tests_enabled == false")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
*/
package org.elasticsearch.xpack.core.security.action.saml;

import org.elasticsearch.Version;
import org.elasticsearch.action.ActionRequest;
import org.elasticsearch.action.ActionRequestValidationException;
import org.elasticsearch.common.Nullable;
Expand All @@ -24,10 +25,16 @@ public final class SamlPrepareAuthenticationRequest extends ActionRequest {
@Nullable
private String assertionConsumerServiceURL;

@Nullable
private String relayState;

public SamlPrepareAuthenticationRequest(StreamInput in) throws IOException {
super(in);
realmName = in.readOptionalString();
assertionConsumerServiceURL = in.readOptionalString();
if (in.getVersion().onOrAfter(Version.V_7_5_0)) {
relayState = in.readOptionalString();
}
}

public SamlPrepareAuthenticationRequest() {
Expand All @@ -54,11 +61,20 @@ public void setAssertionConsumerServiceURL(String assertionConsumerServiceURL) {
this.assertionConsumerServiceURL = assertionConsumerServiceURL;
}

public String getRelayState() {
return relayState;
}

public void setRelayState(String relayState) {
this.relayState = relayState;
}

@Override
public String toString() {
return getClass().getSimpleName() + "{" +
"realmName=" + realmName +
", assertionConsumerServiceURL=" + assertionConsumerServiceURL +
", relayState=" + relayState +
'}';
}

Expand All @@ -67,5 +83,8 @@ public void writeTo(StreamOutput out) throws IOException {
super.writeTo(out);
out.writeOptionalString(realmName);
out.writeOptionalString(assertionConsumerServiceURL);
if (out.getVersion().onOrAfter(Version.V_7_5_0)) {
out.writeOptionalString(relayState);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,14 +49,14 @@ protected void doExecute(Task task, SamlPrepareAuthenticationRequest request,
} else if (realms.size() > 1) {
listener.onFailure(SamlUtils.samlException("Found multiple matching realms [{}] for [{}]", realms, request));
} else {
prepareAuthentication(realms.get(0), listener);
prepareAuthentication(realms.get(0), request.getRelayState(), listener);
}
}

private void prepareAuthentication(SamlRealm realm, ActionListener<SamlPrepareAuthenticationResponse> listener) {
private void prepareAuthentication(SamlRealm realm, String relayState, ActionListener<SamlPrepareAuthenticationResponse> listener) {
final AuthnRequest authnRequest = realm.buildAuthenticationRequest();
try {
String redirectUrl = new SamlRedirect(authnRequest, realm.getSigningConfiguration()).getRedirectUrl();
String redirectUrl = new SamlRedirect(authnRequest, realm.getSigningConfiguration()).getRedirectUrl(relayState);
listener.onResponse(new SamlPrepareAuthenticationResponse(
realm.name(),
authnRequest.getID(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public class SamlRedirect {
private final SAMLObject samlObject;
private final String destination;
private final String parameterName;
private final SigningConfiguration signing;
private final SigningConfiguration signing;

public SamlRedirect(RequestAbstractType request, SigningConfiguration signing) {
this.samlObject = request;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ public class RestSamlPrepareAuthenticationAction extends SamlBaseRestHandler {
static {
PARSER.declareString(SamlPrepareAuthenticationRequest::setAssertionConsumerServiceURL, new ParseField("acs"));
PARSER.declareString(SamlPrepareAuthenticationRequest::setRealmName, new ParseField("realm"));
PARSER.declareString(SamlPrepareAuthenticationRequest::setRelayState, new ParseField("relay_state"));
}

public RestSamlPrepareAuthenticationAction(Settings settings, RestController controller, XPackLicenseState licenseState) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,15 @@ public void testSerialiseNonNullCriteria() throws IOException {
final SamlPrepareAuthenticationRequest req = new SamlPrepareAuthenticationRequest();
req.setRealmName("saml1");
req.setAssertionConsumerServiceURL("https://sp.example.com/sso/saml2/post");
req.setRelayState("the_relay_state");
serialiseAndValidate(req);
}

public void testSerialiseNullCriteria() throws IOException {
final SamlPrepareAuthenticationRequest req = new SamlPrepareAuthenticationRequest();
req.setRealmName(null);
req.setAssertionConsumerServiceURL(null);
req.setRelayState(null);
serialiseAndValidate(req);
}

Expand All @@ -36,7 +38,8 @@ private void serialiseAndValidate(SamlPrepareAuthenticationRequest req1) throws

assertThat(req2.getRealmName(), Matchers.equalTo(req1.getRealmName()));
assertThat(req2.getAssertionConsumerServiceURL(), Matchers.equalTo(req1.getAssertionConsumerServiceURL()));
assertThat(req2.getRelayState(), Matchers.equalTo(req1.getRelayState()));
assertThat(req2.getParentTask(), Matchers.equalTo(req1.getParentTask()));
}

}
}

0 comments on commit 811a148

Please sign in to comment.