-
Notifications
You must be signed in to change notification settings - Fork 264
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
add form-url-encoded body filter #366
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,6 +6,7 @@ | |
import java.util.HashSet; | ||
import java.util.Set; | ||
import java.util.function.Predicate; | ||
import java.util.function.UnaryOperator; | ||
import java.util.regex.Pattern; | ||
|
||
import static java.util.stream.Collectors.joining; | ||
|
@@ -29,11 +30,20 @@ public static BodyFilter defaultValue() { | |
public static BodyFilter accessToken() { | ||
final Set<String> properties = new HashSet<>(); | ||
properties.add("access_token"); | ||
properties.add("refresh_token"); | ||
properties.add("open_id"); | ||
properties.add("id_token"); | ||
return replaceJsonStringProperty(properties, "XXX"); | ||
} | ||
|
||
@API(status = EXPERIMENTAL) | ||
public static BodyFilter oauthRequest() { | ||
final Set<String> properties = new HashSet<>(); | ||
properties.add("client_secret"); | ||
properties.add("password"); | ||
return replaceFormUrlEncodedProperty(properties, "XXX"); | ||
} | ||
|
||
/** | ||
* Creates a {@link BodyFilter} that replaces the properties in the json response with the replacement passed as argument. | ||
* This {@link BodyFilter} works on all levels inside the json tree and it only works with string values<br><br> | ||
|
@@ -52,15 +62,32 @@ public static BodyFilter accessToken() { | |
*/ | ||
@API(status = MAINTAINED) | ||
public static BodyFilter replaceJsonStringProperty(final Set<String> properties, final String replacement) { | ||
final String regex = properties.stream() | ||
.map(Pattern::quote) | ||
.collect(joining("|")); | ||
|
||
final Predicate<String> json = MediaTypeQuery.compile("application/json", "application/*+json"); | ||
|
||
final String regex = properties.stream().map(Pattern::quote).collect(joining("|")); | ||
final Pattern pattern = Pattern.compile("(\"(?:" + regex + ")\"\\s*:\\s*)\".*?\""); | ||
final UnaryOperator<String> delegate = body -> pattern.matcher(body).replaceAll("$1\"" + replacement + "\""); | ||
|
||
return (contentType, body) -> json.test(contentType) ? delegate.apply(body) : body; | ||
} | ||
|
||
/** | ||
* Creates a {@link BodyFilter} that replaces the properties in the form url encoded body with given replacement. | ||
* | ||
* @param properties query names properties to replace | ||
* @param replacement String to replace the properties values | ||
* @return BodyFilter generated | ||
*/ | ||
@API(status = EXPERIMENTAL) | ||
public static BodyFilter replaceFormUrlEncodedProperty(final Set<String> properties, final String replacement) { | ||
final Predicate<String> formUrlEncoded = MediaTypeQuery.compile("application/x-www-form-urlencoded"); | ||
|
||
final QueryFilter delegate = properties.stream() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It works since the query string and the form bodies are encoded in the same way. Should we extract this parsing/transformation from query filter into a separate, shared unit? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
.map(name -> QueryFilters.replaceQuery(name, replacement)) | ||
.reduce(QueryFilter::merge) | ||
.orElseGet(QueryFilter::none); | ||
|
||
return (contentType, body) -> json.test(contentType) ? | ||
pattern.matcher(body).replaceAll("$1\"" + replacement + "\"") : body; | ||
return (contentType, body) -> formUrlEncoded.test(contentType) ? delegate.filter(body) : body; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we have a private, shared method that takes a Predicate and a UnaryOperator and produces a BodyFilter? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't see some reasons to do that - ternary operator quite readable itself. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I feel like it's a quite common pattern, almost suggested by the BodyFilter API since it passes the content type for exactly that reason. |
||
} | ||
|
||
@API(status = EXPERIMENTAL) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is that standardized?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
according to client-credentials and password flows those parameters looks quite standardised. Also I think it makes sense to add filtering out
refresh_token
formaccessToken()
cause it in the end have much higher risks thataccess_token
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
according to w3.org:
x-ww-form-urlencoded
should follow RFC-1738, that describes URL formats.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That one doesn't describe query parameters, does it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't find anything query parameter related in there.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would agree that rfc is quite unreadable. Therefore there is a part describes encoding part as well as format of HTTP URL
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For example RFC2396 mentioned in
java.net.URL
provides almost same ideaThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So, how I personally understand it.
x-www-form-urlencoded
bodies should follow same RFCs, those describe URL format. Both (URI and URL) RFCs describes same for query|search part.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Guys, what about
refresh_token
? Did you consciously decide not to obfuscate it? I just stumbled upon the fact that the refresh token appears in our logs....Currently I would need to configure a custom
BodyFilter
bean: