Skip to content

Commit

Permalink
Prefer 303 over 302 for redirecting after a POST (#1223)
Browse files Browse the repository at this point in the history
* Prefer 303 over 302 for redirecting after a POST

* update release notes

* Update release-notes.md

* rename TemporaryRedirectAction as FoundAction (302), the real RFC name
  • Loading branch information
leleuj committed Dec 21, 2018
1 parent 7398951 commit 3ebc984
Show file tree
Hide file tree
Showing 54 changed files with 217 additions and 171 deletions.
1 change: 1 addition & 0 deletions documentation/docs/release-notes.md
Expand Up @@ -10,6 +10,7 @@ title: Release notes:
- Updated the OpenID Connect/JWT dependencies - Updated the OpenID Connect/JWT dependencies
- A client can return any kind of profile (using a custom `AuthorizationGenerator` or `ProfileCreator`) and even a minimal user profile (`UserProfile`) - A client can return any kind of profile (using a custom `AuthorizationGenerator` or `ProfileCreator`) and even a minimal user profile (`UserProfile`)
- Multiple HTTP actions (inheriting from `HttpAction`) are created to handle the necessary HTTP actions. They are only applied to the web context by the appropriate `HttpActionAdapter`. The `RedirectAction` is replaced by the new HTTP actions inheriting from `RedirectionAction` - Multiple HTTP actions (inheriting from `HttpAction`) are created to handle the necessary HTTP actions. They are only applied to the web context by the appropriate `HttpActionAdapter`. The `RedirectAction` is replaced by the new HTTP actions inheriting from `RedirectionAction`
- Use the 303 "See Other" HTTP action instead of the 302 "Temporary Redirect" HTTP action for any redirection after a POST request in the `DefaultCallbackLogic`




**v3.5.0**: **v3.5.0**:
Expand Down
Expand Up @@ -12,7 +12,7 @@
import org.pac4j.core.credentials.extractor.ParameterExtractor; import org.pac4j.core.credentials.extractor.ParameterExtractor;
import org.pac4j.core.exception.CredentialsException; import org.pac4j.core.exception.CredentialsException;
import org.pac4j.core.exception.TechnicalException; import org.pac4j.core.exception.TechnicalException;
import org.pac4j.core.exception.http.TemporaryRedirectAction; import org.pac4j.core.exception.http.FoundAction;
import org.pac4j.core.http.callback.CallbackUrlResolver; import org.pac4j.core.http.callback.CallbackUrlResolver;
import org.pac4j.core.http.callback.NoParameterCallbackUrlResolver; import org.pac4j.core.http.callback.NoParameterCallbackUrlResolver;
import org.pac4j.core.http.url.DefaultUrlResolver; import org.pac4j.core.http.url.DefaultUrlResolver;
Expand Down Expand Up @@ -77,7 +77,7 @@ protected TokenCredentials retrieveCredentials(final WebContext context) {
final String redirectionUrl = CommonUtils.constructRedirectUrl(loginUrl, CasConfiguration.SERVICE_PARAMETER, final String redirectionUrl = CommonUtils.constructRedirectUrl(loginUrl, CasConfiguration.SERVICE_PARAMETER,
callbackUrl, configuration.isRenew(), false); callbackUrl, configuration.isRenew(), false);
logger.debug("redirectionUrl: {}", redirectionUrl); logger.debug("redirectionUrl: {}", redirectionUrl);
throw new TemporaryRedirectAction(redirectionUrl); throw new FoundAction(redirectionUrl);
} }


// clean url from ticket parameter // clean url from ticket parameter
Expand Down
Expand Up @@ -4,7 +4,7 @@
import org.jasig.cas.client.util.CommonUtils; import org.jasig.cas.client.util.CommonUtils;
import org.pac4j.cas.config.CasConfiguration; import org.pac4j.cas.config.CasConfiguration;
import org.pac4j.core.exception.http.NoContentAction; import org.pac4j.core.exception.http.NoContentAction;
import org.pac4j.core.exception.http.TemporaryRedirectAction; import org.pac4j.core.exception.http.FoundAction;
import org.pac4j.core.logout.handler.LogoutHandler; import org.pac4j.core.logout.handler.LogoutHandler;
import org.pac4j.core.context.ContextHelper; import org.pac4j.core.context.ContextHelper;
import org.pac4j.core.context.HttpConstants; import org.pac4j.core.context.HttpConstants;
Expand Down Expand Up @@ -135,7 +135,7 @@ private void computeRedirectionToServerIfNecessary(final WebContext context) {
buffer.append(CommonUtils.urlEncode(relayStateValue)); buffer.append(CommonUtils.urlEncode(relayStateValue));
final String redirectUrl = buffer.toString(); final String redirectUrl = buffer.toString();
logger.debug("Redirection url to the CAS server: {}", redirectUrl); logger.debug("Redirection url to the CAS server: {}", redirectUrl);
throw new TemporaryRedirectAction(redirectUrl); throw new FoundAction(redirectUrl);
} }
} }
} }
Expand Up @@ -4,7 +4,7 @@
import org.pac4j.cas.client.CasClient; import org.pac4j.cas.client.CasClient;
import org.pac4j.cas.config.CasConfiguration; import org.pac4j.cas.config.CasConfiguration;
import org.pac4j.core.exception.http.RedirectionAction; import org.pac4j.core.exception.http.RedirectionAction;
import org.pac4j.core.exception.http.TemporaryRedirectAction; import org.pac4j.core.exception.http.FoundAction;
import org.pac4j.core.context.WebContext; import org.pac4j.core.context.WebContext;
import org.pac4j.core.redirect.RedirectionActionBuilder; import org.pac4j.core.redirect.RedirectionActionBuilder;
import org.pac4j.core.util.CommonHelper; import org.pac4j.core.util.CommonHelper;
Expand Down Expand Up @@ -39,6 +39,6 @@ public RedirectionAction redirect(final WebContext context) {
final String redirectionUrl = CommonUtils.constructRedirectUrl(computeLoginUrl, CasConfiguration.SERVICE_PARAMETER, final String redirectionUrl = CommonUtils.constructRedirectUrl(computeLoginUrl, CasConfiguration.SERVICE_PARAMETER,
computedCallbackUrl, configuration.isRenew(), configuration.isGateway()); computedCallbackUrl, configuration.isRenew(), configuration.isGateway());
logger.debug("redirectionUrl: {}", redirectionUrl); logger.debug("redirectionUrl: {}", redirectionUrl);
return new TemporaryRedirectAction(redirectionUrl); return new FoundAction(redirectionUrl);
} }
} }
12 changes: 6 additions & 6 deletions pac4j-cas/src/test/java/org/pac4j/cas/client/CasClientTests.java
Expand Up @@ -6,7 +6,7 @@
import org.pac4j.core.context.WebContext; import org.pac4j.core.context.WebContext;
import org.pac4j.core.credentials.TokenCredentials; import org.pac4j.core.credentials.TokenCredentials;
import org.pac4j.core.exception.http.HttpAction; import org.pac4j.core.exception.http.HttpAction;
import org.pac4j.core.exception.http.TemporaryRedirectAction; import org.pac4j.core.exception.http.FoundAction;
import org.pac4j.core.http.callback.CallbackUrlResolver; import org.pac4j.core.http.callback.CallbackUrlResolver;
import org.pac4j.core.http.url.UrlResolver; import org.pac4j.core.http.url.UrlResolver;
import org.pac4j.core.util.TestsConstants; import org.pac4j.core.util.TestsConstants;
Expand Down Expand Up @@ -110,7 +110,7 @@ public void testRenewMissing() {
final CasClient casClient = new CasClient(configuration); final CasClient casClient = new CasClient(configuration);
casClient.setCallbackUrl(CALLBACK_URL); casClient.setCallbackUrl(CALLBACK_URL);
final MockWebContext context = MockWebContext.create(); final MockWebContext context = MockWebContext.create();
final TemporaryRedirectAction action = (TemporaryRedirectAction) casClient.redirect(context); final FoundAction action = (FoundAction) casClient.redirect(context);
assertFalse(action.getLocation().indexOf("renew=true") >= 0); assertFalse(action.getLocation().indexOf("renew=true") >= 0);
} }


Expand All @@ -122,7 +122,7 @@ public void testRenew() {
casClient.setCallbackUrl(CALLBACK_URL); casClient.setCallbackUrl(CALLBACK_URL);
configuration.setRenew(true); configuration.setRenew(true);
final MockWebContext context = MockWebContext.create(); final MockWebContext context = MockWebContext.create();
final TemporaryRedirectAction action = (TemporaryRedirectAction) casClient.redirect(context); final FoundAction action = (FoundAction) casClient.redirect(context);
assertTrue(action.getLocation().indexOf("renew=true") >= 0); assertTrue(action.getLocation().indexOf("renew=true") >= 0);
} }


Expand All @@ -133,7 +133,7 @@ public void testGatewayMissing() {
final CasClient casClient = new CasClient(configuration); final CasClient casClient = new CasClient(configuration);
casClient.setCallbackUrl(CALLBACK_URL); casClient.setCallbackUrl(CALLBACK_URL);
final MockWebContext context = MockWebContext.create(); final MockWebContext context = MockWebContext.create();
final TemporaryRedirectAction action = (TemporaryRedirectAction) casClient.redirect(context); final FoundAction action = (FoundAction) casClient.redirect(context);
assertFalse(action.getLocation().indexOf("gateway=true") >= 0); assertFalse(action.getLocation().indexOf("gateway=true") >= 0);
} }


Expand All @@ -145,7 +145,7 @@ public void testGatewayOK() {
casClient.setCallbackUrl(CALLBACK_URL); casClient.setCallbackUrl(CALLBACK_URL);
final MockWebContext context = MockWebContext.create(); final MockWebContext context = MockWebContext.create();
configuration.setGateway(true); configuration.setGateway(true);
final TemporaryRedirectAction action = (TemporaryRedirectAction) casClient.redirect(context); final FoundAction action = (FoundAction) casClient.redirect(context);
assertTrue(action.getLocation().indexOf("gateway=true") >= 0); assertTrue(action.getLocation().indexOf("gateway=true") >= 0);
final TokenCredentials credentials = casClient.getCredentials(context); final TokenCredentials credentials = casClient.getCredentials(context);
assertNull(credentials); assertNull(credentials);
Expand Down Expand Up @@ -200,7 +200,7 @@ public void testFrontLogoutWithRelayState() {
.addRequestParameter(CasConfiguration.LOGOUT_REQUEST_PARAMETER, deflateAndBase64(LOGOUT_MESSAGE)) .addRequestParameter(CasConfiguration.LOGOUT_REQUEST_PARAMETER, deflateAndBase64(LOGOUT_MESSAGE))
.addRequestParameter(CasConfiguration.RELAY_STATE_PARAMETER, VALUE).setRequestMethod(HTTP_METHOD.GET.name()); .addRequestParameter(CasConfiguration.RELAY_STATE_PARAMETER, VALUE).setRequestMethod(HTTP_METHOD.GET.name());
final HttpAction action = (HttpAction) TestsHelper.expectException(() -> casClient.getCredentials(context)); final HttpAction action = (HttpAction) TestsHelper.expectException(() -> casClient.getCredentials(context));
assertEquals(TEMP_REDIRECT, action.getCode()); assertEquals(FOUND, action.getCode());
} }


@Test @Test
Expand Down
Expand Up @@ -8,7 +8,7 @@
import org.pac4j.core.credentials.TokenCredentials; import org.pac4j.core.credentials.TokenCredentials;
import org.pac4j.core.exception.http.HttpAction; import org.pac4j.core.exception.http.HttpAction;
import org.pac4j.core.exception.TechnicalException; import org.pac4j.core.exception.TechnicalException;
import org.pac4j.core.exception.http.TemporaryRedirectAction; import org.pac4j.core.exception.http.FoundAction;
import org.pac4j.core.profile.CommonProfile; import org.pac4j.core.profile.CommonProfile;
import org.pac4j.core.util.TestsConstants; import org.pac4j.core.util.TestsConstants;
import org.pac4j.core.util.TestsHelper; import org.pac4j.core.util.TestsHelper;
Expand Down Expand Up @@ -58,7 +58,7 @@ public void testNoTokenRedirectionExpected() {
final HttpAction action = (HttpAction) TestsHelper.expectException(() -> client.getCredentials(context)); final HttpAction action = (HttpAction) TestsHelper.expectException(() -> client.getCredentials(context));
assertEquals(302, action.getCode()); assertEquals(302, action.getCode());
assertEquals(addParameter(LOGIN_URL, CasConfiguration.SERVICE_PARAMETER, CALLBACK_URL), assertEquals(addParameter(LOGIN_URL, CasConfiguration.SERVICE_PARAMETER, CALLBACK_URL),
((TemporaryRedirectAction) action).getLocation()); ((FoundAction) action).getLocation());
} }


@Test @Test
Expand Down
@@ -1,7 +1,7 @@
package org.pac4j.core.authorization.authorizer; package org.pac4j.core.authorization.authorizer;


import org.pac4j.core.context.WebContext; import org.pac4j.core.context.WebContext;
import org.pac4j.core.exception.http.TemporaryRedirectAction; import org.pac4j.core.exception.http.FoundAction;
import org.pac4j.core.profile.UserProfile; import org.pac4j.core.profile.UserProfile;


/** /**
Expand All @@ -23,7 +23,7 @@ public AbstractCheckAuthenticationAuthorizer(final String redirectionUrl) {
@Override @Override
protected boolean handleError(final WebContext context) { protected boolean handleError(final WebContext context) {
if (this.redirectionUrl != null) { if (this.redirectionUrl != null) {
throw new TemporaryRedirectAction(this.redirectionUrl); throw new FoundAction(this.redirectionUrl);
} else { } else {
return false; return false;
} }
Expand Down
Expand Up @@ -18,7 +18,9 @@ public interface HttpConstants {


int FORBIDDEN = 403; int FORBIDDEN = 403;


int TEMP_REDIRECT = 302; int FOUND = 302;

int SEE_OTHER = 303;


int BAD_REQUEST = 400; int BAD_REQUEST = 400;


Expand Down
Expand Up @@ -2,7 +2,7 @@


import org.pac4j.core.context.WebContext; import org.pac4j.core.context.WebContext;
import org.pac4j.core.exception.http.HttpAction; import org.pac4j.core.exception.http.HttpAction;
import org.pac4j.core.exception.http.TemporaryRedirectAction; import org.pac4j.core.exception.http.FoundAction;
import org.pac4j.core.http.adapter.HttpActionAdapter; import org.pac4j.core.http.adapter.HttpActionAdapter;
import org.pac4j.core.profile.factory.ProfileManagerFactoryAware; import org.pac4j.core.profile.factory.ProfileManagerFactoryAware;
import org.pac4j.core.util.CommonHelper; import org.pac4j.core.util.CommonHelper;
Expand Down Expand Up @@ -43,7 +43,7 @@ protected R handleException(final Exception e, final HttpActionAdapter<R, C> htt
return httpActionAdapter.adapt(action, context); return httpActionAdapter.adapt(action, context);
} else { } else {
if (CommonHelper.isNotBlank(errorUrl)) { if (CommonHelper.isNotBlank(errorUrl)) {
final HttpAction action = new TemporaryRedirectAction(errorUrl); final HttpAction action = new FoundAction(errorUrl);
return httpActionAdapter.adapt(action, context); return httpActionAdapter.adapt(action, context);
} else { } else {
throw runtimeException(e); throw runtimeException(e);
Expand Down
Expand Up @@ -7,12 +7,14 @@
import org.pac4j.core.client.finder.ClientFinder; import org.pac4j.core.client.finder.ClientFinder;
import org.pac4j.core.client.finder.DefaultCallbackClientFinder; import org.pac4j.core.client.finder.DefaultCallbackClientFinder;
import org.pac4j.core.config.Config; import org.pac4j.core.config.Config;
import org.pac4j.core.context.ContextHelper;
import org.pac4j.core.context.Pac4jConstants; import org.pac4j.core.context.Pac4jConstants;
import org.pac4j.core.context.WebContext; import org.pac4j.core.context.WebContext;
import org.pac4j.core.context.session.SessionStore; import org.pac4j.core.context.session.SessionStore;
import org.pac4j.core.credentials.Credentials; import org.pac4j.core.credentials.Credentials;
import org.pac4j.core.exception.http.HttpAction; import org.pac4j.core.exception.http.HttpAction;
import org.pac4j.core.exception.http.TemporaryRedirectAction; import org.pac4j.core.exception.http.SeeOtherAction;
import org.pac4j.core.exception.http.FoundAction;
import org.pac4j.core.http.adapter.HttpActionAdapter; import org.pac4j.core.http.adapter.HttpActionAdapter;
import org.pac4j.core.profile.ProfileManager; import org.pac4j.core.profile.ProfileManager;
import org.pac4j.core.profile.UserProfile; import org.pac4j.core.profile.UserProfile;
Expand Down Expand Up @@ -145,7 +147,11 @@ protected HttpAction redirectToOriginallyRequestedUrl(final C context, final Str
redirectUrl = requestedUrl; redirectUrl = requestedUrl;
} }
logger.debug("redirectUrl: {}", redirectUrl); logger.debug("redirectUrl: {}", redirectUrl);
return new TemporaryRedirectAction(redirectUrl); if (ContextHelper.isPost(context)) {
return new SeeOtherAction(redirectUrl);
} else {
return new FoundAction(redirectUrl);
}
} }


public ClientFinder getClientFinder() { public ClientFinder getClientFinder() {
Expand Down
Expand Up @@ -10,7 +10,7 @@
import org.pac4j.core.exception.http.HttpAction; import org.pac4j.core.exception.http.HttpAction;
import org.pac4j.core.exception.http.NoContentAction; import org.pac4j.core.exception.http.NoContentAction;
import org.pac4j.core.exception.http.RedirectionAction; import org.pac4j.core.exception.http.RedirectionAction;
import org.pac4j.core.exception.http.TemporaryRedirectAction; import org.pac4j.core.exception.http.FoundAction;
import org.pac4j.core.http.adapter.HttpActionAdapter; import org.pac4j.core.http.adapter.HttpActionAdapter;
import org.pac4j.core.profile.CommonProfile; import org.pac4j.core.profile.CommonProfile;
import org.pac4j.core.profile.ProfileManager; import org.pac4j.core.profile.ProfileManager;
Expand Down Expand Up @@ -94,7 +94,7 @@ public R perform(final C context, final Config config, final HttpActionAdapter<R
} }
logger.debug("redirectUrl: {}", redirectUrl); logger.debug("redirectUrl: {}", redirectUrl);
if (redirectUrl != null) { if (redirectUrl != null) {
action = new TemporaryRedirectAction(redirectUrl); action = new FoundAction(redirectUrl);
} else { } else {
action = NoContentAction.INSTANCE; action = NoContentAction.INSTANCE;
} }
Expand Down
Expand Up @@ -3,17 +3,17 @@
import org.pac4j.core.context.HttpConstants; import org.pac4j.core.context.HttpConstants;


/** /**
* A temporary redirect HTTP action. * A "Found" HTTP action.
* *
* @author Jerome Leleu * @author Jerome Leleu
* @since 4.0.0 * @since 4.0.0
*/ */
public class TemporaryRedirectAction extends RedirectionAction { public class FoundAction extends RedirectionAction {


private final String location; private final String location;


public TemporaryRedirectAction(final String location) { public FoundAction(final String location) {
super(HttpConstants.TEMP_REDIRECT); super(HttpConstants.FOUND);
this.location = location; this.location = location;
} }


Expand Down
@@ -0,0 +1,23 @@
package org.pac4j.core.exception.http;

import org.pac4j.core.context.HttpConstants;

/**
* A "See Other" HTTP action.
*
* @author Jerome Leleu
* @since 4.0.0
*/
public class SeeOtherAction extends RedirectionAction {

private final String location;

public SeeOtherAction(final String location) {
super(HttpConstants.SEE_OTHER);
this.location = location;
}

public String getLocation() {
return location;
}
}
Expand Up @@ -3,10 +3,7 @@
import org.pac4j.core.context.HttpConstants; import org.pac4j.core.context.HttpConstants;
import org.pac4j.core.context.JEEContext; import org.pac4j.core.context.JEEContext;
import org.pac4j.core.exception.TechnicalException; import org.pac4j.core.exception.TechnicalException;
import org.pac4j.core.exception.http.HttpAction; import org.pac4j.core.exception.http.*;
import org.pac4j.core.exception.http.NoContentAction;
import org.pac4j.core.exception.http.OkAction;
import org.pac4j.core.exception.http.TemporaryRedirectAction;


/** /**
* The HTTP action adapter for the {@link JEEContext}. * The HTTP action adapter for the {@link JEEContext}.
Expand All @@ -27,8 +24,10 @@ public Object adapt(final HttpAction action, final JEEContext context) {
context.writeResponseContent(""); context.writeResponseContent("");
} else if (action instanceof OkAction) { } else if (action instanceof OkAction) {
context.writeResponseContent(((OkAction) action).getContent()); context.writeResponseContent(((OkAction) action).getContent());
} else if (action instanceof TemporaryRedirectAction) { } else if (action instanceof FoundAction) {
context.setResponseHeader(HttpConstants.LOCATION_HEADER, ((TemporaryRedirectAction) action).getLocation()); context.setResponseHeader(HttpConstants.LOCATION_HEADER, ((FoundAction) action).getLocation());
} else if (action instanceof SeeOtherAction) {
context.setResponseHeader(HttpConstants.LOCATION_HEADER, ((SeeOtherAction) action).getLocation());
} }


return null; return null;
Expand Down
Expand Up @@ -24,11 +24,11 @@ public boolean isAjax(final WebContext context) {


@Override @Override
public HttpAction buildAjaxResponse(final RedirectionAction action, final WebContext context) { public HttpAction buildAjaxResponse(final RedirectionAction action, final WebContext context) {
if (!(action instanceof TemporaryRedirectAction)) { if (!(action instanceof FoundAction)) {
throw UnauthorizedAction.INSTANCE; throw UnauthorizedAction.INSTANCE;
} }


final String url = ((TemporaryRedirectAction) action).getLocation(); final String url = ((FoundAction) action).getLocation();


if ( CommonHelper.isBlank(context.getRequestParameter(FACES_PARTIAL_AJAX_PARAMETER))) { if ( CommonHelper.isBlank(context.getRequestParameter(FACES_PARTIAL_AJAX_PARAMETER))) {
if (CommonHelper.isNotBlank(url)) { if (CommonHelper.isNotBlank(url)) {
Expand Down
@@ -1,7 +1,7 @@
package org.pac4j.core.logout; package org.pac4j.core.logout;


import org.pac4j.core.exception.http.RedirectionAction; import org.pac4j.core.exception.http.RedirectionAction;
import org.pac4j.core.exception.http.TemporaryRedirectAction; import org.pac4j.core.exception.http.FoundAction;
import org.pac4j.core.profile.UserProfile; import org.pac4j.core.profile.UserProfile;
import org.pac4j.core.context.WebContext; import org.pac4j.core.context.WebContext;


Expand Down Expand Up @@ -43,7 +43,7 @@ public RedirectionAction getLogoutAction(final WebContext context, final UserPro
redirectUrl = addParameter(redirectUrl, postLogoutUrlParameter, targetUrl); redirectUrl = addParameter(redirectUrl, postLogoutUrlParameter, targetUrl);
} }
logger.debug("redirectUrl: {}", redirectUrl); logger.debug("redirectUrl: {}", redirectUrl);
return new TemporaryRedirectAction(redirectUrl); return new FoundAction(redirectUrl);
} }


@Override @Override
Expand Down
Expand Up @@ -2,7 +2,7 @@


import org.pac4j.core.context.WebContext; import org.pac4j.core.context.WebContext;
import org.pac4j.core.exception.http.RedirectionAction; import org.pac4j.core.exception.http.RedirectionAction;
import org.pac4j.core.exception.http.TemporaryRedirectAction; import org.pac4j.core.exception.http.FoundAction;
import org.pac4j.core.profile.UserProfile; import org.pac4j.core.profile.UserProfile;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
Expand All @@ -22,6 +22,6 @@ public RedirectionAction getLogoutAction(final WebContext context, final UserPro


final String redirectUrl = "https://accounts.google.com/Logout"; final String redirectUrl = "https://accounts.google.com/Logout";
logger.debug("redirectUrl: {}", redirectUrl); logger.debug("redirectUrl: {}", redirectUrl);
return new TemporaryRedirectAction(redirectUrl); return new FoundAction(redirectUrl);
} }
} }

0 comments on commit 3ebc984

Please sign in to comment.