For post logout redirect URI - Make '+' represent existing redirect URIs and merge with existing post logout redirect URIs

Closes keycloak#25544

Signed-off-by: Joshua Sorah <jsorah@redhat.com>
This commit is contained in:
Joshua Sorah 2023-12-13 17:30:20 -05:00 committed by Marek Posolda
parent 367d0a9868
commit a10149bbe9
2 changed files with 80 additions and 1 deletions

View file

@ -27,6 +27,8 @@ import org.keycloak.utils.StringUtil;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
/** /**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a> * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
@ -378,7 +380,7 @@ public class OIDCAdvancedConfigWrapper extends AbstractClientConfigWrapper {
public List<String> getPostLogoutRedirectUris() { public List<String> getPostLogoutRedirectUris() {
List<String> postLogoutRedirectUris = getAttributeMultivalued(OIDCConfigAttributes.POST_LOGOUT_REDIRECT_URIS); List<String> postLogoutRedirectUris = getAttributeMultivalued(OIDCConfigAttributes.POST_LOGOUT_REDIRECT_URIS);
if(postLogoutRedirectUris == null || postLogoutRedirectUris.isEmpty() || postLogoutRedirectUris.get(0).equals("+")) { if(postLogoutRedirectUris == null || postLogoutRedirectUris.isEmpty()) {
if(clientModel != null) { if(clientModel != null) {
return new ArrayList(clientModel.getRedirectUris()); return new ArrayList(clientModel.getRedirectUris());
} }
@ -390,6 +392,18 @@ public class OIDCAdvancedConfigWrapper extends AbstractClientConfigWrapper {
else if(postLogoutRedirectUris.get(0).equals("-")) { else if(postLogoutRedirectUris.get(0).equals("-")) {
return new ArrayList<String>(); return new ArrayList<String>();
} }
else if (postLogoutRedirectUris.contains("+")) {
Set<String> returnedPostLogoutRedirectUris = postLogoutRedirectUris.stream()
.filter(uri -> !"+".equals(uri)).collect(Collectors.toSet());
if(clientModel != null) {
returnedPostLogoutRedirectUris.addAll(clientModel.getRedirectUris());
}
else if(clientRep != null) {
returnedPostLogoutRedirectUris.addAll(clientRep.getRedirectUris());
}
return new ArrayList<>(returnedPostLogoutRedirectUris);
}
else { else {
return postLogoutRedirectUris; return postLogoutRedirectUris;
} }

View file

@ -98,6 +98,8 @@ import org.openqa.selenium.NoSuchElementException;
*/ */
public class RPInitiatedLogoutTest extends AbstractTestRealmKeycloakTest { public class RPInitiatedLogoutTest extends AbstractTestRealmKeycloakTest {
public static final String DUMMY_POST_LOGOUT_URI = "http://127.0.0.1:4321/thisisatest";
@Rule @Rule
public AssertEvents events = new AssertEvents(this); public AssertEvents events = new AssertEvents(this);
@ -720,6 +722,50 @@ public class RPInitiatedLogoutTest extends AbstractTestRealmKeycloakTest {
assertCurrentUrlEquals(APP_REDIRECT_URI + "?state=something2"); assertCurrentUrlEquals(APP_REDIRECT_URI + "?state=something2");
} }
@Test
public void logoutWithClientIdAndPostLogoutRedirectUriWhenUsingPostLogoutRedirectUriAndPlusFirst() throws IOException {
doLogoutTestWithPostLogoutRedirectAttributeAndSpecifiedPostLogoutRedirectUri(
String.join(Constants.CFG_DELIMITER,
"+",
DUMMY_POST_LOGOUT_URI),
DUMMY_POST_LOGOUT_URI);
}
@Test
public void logoutWithClientIdAndPostLogoutRedirectUriWhenUsingPostLogoutRedirectUriAndPlusLast() throws IOException {
doLogoutTestWithPostLogoutRedirectAttributeAndSpecifiedPostLogoutRedirectUri(
String.join(Constants.CFG_DELIMITER,
DUMMY_POST_LOGOUT_URI,
"+"),
DUMMY_POST_LOGOUT_URI);
}
@Test
public void logoutWithClientIdAndPostLogoutRedirectUriWhenUsingAppRedirectUriAndAdditionalPostLogoutUriAndPlusFirstAndLast() throws IOException {
doLogoutTestWithPostLogoutRedirectAttributeAndSpecifiedPostLogoutRedirectUri(
String.join(Constants.CFG_DELIMITER,
"+",
DUMMY_POST_LOGOUT_URI,
"+"),
APP_REDIRECT_URI);
}
@Test
public void logoutWithClientIdAndPostLogoutRedirectUriWhenUsingAppRedirectUriAndAdditionalPostLogoutUriAndPlusLast() throws IOException {
doLogoutTestWithPostLogoutRedirectAttributeAndSpecifiedPostLogoutRedirectUri(
String.join(Constants.CFG_DELIMITER,
DUMMY_POST_LOGOUT_URI,
"+"),
APP_REDIRECT_URI);
}
@Test
public void logoutWithClientIdAndPostLogoutRedirectUriWhenWhenUsingAppRedirectUriAndPlus() throws IOException {
doLogoutTestWithPostLogoutRedirectAttributeAndSpecifiedPostLogoutRedirectUri(
"+",
APP_REDIRECT_URI);
}
@Test @Test
public void logoutWithBadClientId() { public void logoutWithBadClientId() {
@ -1142,4 +1188,23 @@ public class RPInitiatedLogoutTest extends AbstractTestRealmKeycloakTest {
return false; return false;
} }
} }
private void doLogoutTestWithPostLogoutRedirectAttributeAndSpecifiedPostLogoutRedirectUri(String postLogoutRedirectAttr, String postLogoutRedirectUri) throws IOException {
try (Closeable accountClientUpdater = ClientAttributeUpdater.forClient(adminClient, "test", "test-app" )
.setAttribute(OIDCConfigAttributes.POST_LOGOUT_REDIRECT_URIS, postLogoutRedirectAttr).update()) {
OAuthClient.AccessTokenResponse tokenResponse = loginUser();
String logoutUrl = oauth.getLogoutUrl().postLogoutRedirectUri(postLogoutRedirectUri).clientId("test-app").build();
driver.navigate().to(logoutUrl);
// Assert logout confirmation page as id_token_hint was not sent. Session still exists. Assert default language on logout page (English)
logoutConfirmPage.assertCurrent();
Assert.assertEquals("English", logoutConfirmPage.getLanguageDropdownText());
MatcherAssert.assertThat(true, is(isSessionActive(tokenResponse.getSessionState())));
events.assertEmpty();
// We don't need to go further as the intent is that other tests will cover redirection
}
}
} }