Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Invalid redirect URI error when trying to allow redirect URI with random query parameter #30695

Closed
1 of 2 tasks
bwaldvogel opened this issue Jun 24, 2024 · 5 comments
Closed
1 of 2 tasks
Labels
area/core kind/bug Categorizes a PR related to a bug team/core-shared

Comments

@bwaldvogel
Copy link
Contributor

bwaldvogel commented Jun 24, 2024

Before reporting an issue

  • I have read and understood the above terms for submitting issues, and I understand that my issue may be closed without action if I do not follow them.

Area

core

Describe the bug

I want to configure a "Valid post logout redirect URIs" for URLs with random query parameter such as

http:https://localhost:8080/logout?_csrf=<some-random-string>

I tried the following valid redirect URIs but none of them work

  • http:https://localhost:4000/logout
  • http:https://localhost:4000/logout?*
  • http:https://localhost:4000/logout?_csrf=*

As a workaround I could use

  • http:https://localhost:4000/logout*
    or
  • http:https://localhost:4000/logout/*

but that would also allow redirects to other URLs such as /logout-other or /logout/other, which I don’t want to permit.

I found org.keycloak.protocol.oidc.utils.RedirectUtils#matchesRedirects which seems to strip off the query but only if there’s no question mark (?) in the URI:

// return the String that matched the redirect or null if not matched
private static String matchesRedirects(Set<String> validRedirects, String redirect, boolean allowWildcards) {
	logger.tracef("matchesRedirects: redirect URL to check: %s, allow wildcards: %b, Configured valid redirect URLs: %s", redirect, allowWildcards, validRedirects);
	for (String validRedirect : validRedirects) {
		if ("*".equals(validRedirect)) {
			// the valid redirect * is a full wildcard for http(s) even if the redirect URI does not allow wildcards
			return validRedirect;
		} else if (validRedirect.endsWith("*") && !validRedirect.contains("?") && allowWildcards) {
			// strip off the query or fragment components - we don't check them when wildcards are effective
			int idx = redirect.indexOf('?');
			if (idx == -1) {
				idx = redirect.indexOf('#');
			}
			String r = idx == -1 ? redirect : redirect.substring(0, idx);
			// strip off *
			int length = validRedirect.length() - 1;
			validRedirect = validRedirect.substring(0, length);
			if (r.startsWith(validRedirect)) return validRedirect;
			// strip off trailing '/'
			if (length - 1 > 0 && validRedirect.charAt(length - 1) == '/') length--;
			validRedirect = validRedirect.substring(0, length);
			if (validRedirect.equals(r)) return validRedirect;
		} else if (validRedirect.equals(redirect)) return validRedirect;
	}
	return null;
}

Version

25.0.1

Regression

  • The issue is a regression

Expected behavior

The redirect URI http:https://localhost:8080/logout?_csrf=some-random-string is considered valid when http:https://localhost:8080/logout?* or http:https://localhost:8080/logout?_csrf=* is configured to be a valid redirect URI.

Actual behavior

The http:https://localhost:8080/logout?_csrf=some-random-string URI is rejected with an invalid_redirect_uri error

How to Reproduce?

  1. Configure http:https://localhost:8080/logout?* or http:https://localhost:8080/logout?_csrf=* as "Valid post logout redirect URIs" in the client
  2. Initiate the logout with a random query parameter, for example by navigating to http:https://keycloak:port/realms/my-realm/protocol/openid-connect/logout?client_id=my-client&post_logout_redirect_uri=http:https://localhost:8080/logout?_csrf=e45bb8e8-b3a5-4d5b-9317-72f8d9854489

Anything else?

No response

@bwaldvogel
Copy link
Contributor Author

@rmartinc: I saw that you recently worked on org.keycloak.protocol.oidc.utils.RedirectUtils#matchesRedirects. Maybe you could give me a hint if my described behavior is even intentional or rather a missing feature?

@rmartinc
Copy link
Contributor

Hi @bwaldvogel!

The common (and recommended by OAuth 2.0 Security Best Current Practice and enforced by OAuth 2.1) is using exact redirect URI matching, everything, query parameters included. The only case where keycloak is doing something special, and out of the spec, is when it's using path wildcards (if condition validRedirect.endsWith("*") && !validRedirect.contains("?") && allowWildcards). So the wildcard is only allowed for the path (https://server/path/*) never for the query parameters. It's intentional, we only do something different to recommended exact string matching when using path wildcards, and this is because historical reasons, It is recommended to not use wildcards for valid redirects(see Unspecific redirect URIs in the server guide).

@keycloak-github-bot keycloak-github-bot bot closed this as not planned Won't fix, can't repro, duplicate, stale Jun 24, 2024
@keycloak-github-bot
Copy link

Thanks for reporting this issue. However, after review this is not considered a valid issue, or has been recently resolved.

As the issue is not valid it will be automatically closed.

1 similar comment
@keycloak-github-bot
Copy link

Thanks for reporting this issue. However, after review this is not considered a valid issue, or has been recently resolved.

As the issue is not valid it will be automatically closed.

@bwaldvogel
Copy link
Contributor Author

Ok, thanks for this info.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/core kind/bug Categorizes a PR related to a bug team/core-shared
Projects
None yet
Development

No branches or pull requests

3 participants