How to encode an authorization request_uri - spring

I need to construct a custom request_uri for an implementation of Spring OAuth2. What specific code should be used to properly encode each of the parameters in the request_uri?
The full, unencoded, request_uri is as follows, but is resulting in an error that indicates that a token is not granted:
http://localhost:9999/uaa/oauth/authorize?client_id=acme
&redirect_uri=http://localhost:8080/login&response_type=code
&state=13ab71ae-c8ed-4370-a60f-dd7fe47ed763
As you can see, the individual parameters are:
client_id=acme
redirect_uri=http://localhost:8080/login
response_type=code
state=13ab71ae-c8ed-4370-a60f-dd7fe47ed763
And the code that was used to construct the above request_uri is:
CsrfToken csrf = (CsrfToken) attr.getRequest().getAttribute(CsrfToken.class.getName());
String attrToken = csrf.getToken();
authorizationRequest.setState(attrToken);
String newRequestUri = "http://localhost:9999/uaa/oauth/authorize?";
String clientId = authorizationRequest.getClientId();
newRequestUri = newRequestUri + "client_id=" + clientId;
String redirectUri = authorizationRequest.getRedirectUri();
newRequestUri = newRequestUri + "&redirect_uri="+redirectUri;
Set<String> respTypes = authorizationRequest.getResponseTypes();
String respType = respTypes.iterator().next();//this plucks the first one, but is not safe for when there is a list.
newRequestUri = newRequestUri +"&response_type="+respType;
String state = authorizationRequest.getState();
newRequestUri = newRequestUri + "&state="+state;
attr.setAttribute("javax.servlet.forward.request_uri", newRequestUri, RequestAttributes.SCOPE_REQUEST);
//now re-set the request attributes to reflect the changes we just made
RequestContextHolder.setRequestAttributes(attr);
More specifically, this OP asks what syntax should be used to encode the following string values in the code above: newRequestUri, clientId, redirectUri, respType, and state.
The Official OAuth2 Spec says you can use the application/x-www-form-urlencoded Content-Type and UTF-8 encoding, but then also gives this example:
/authorize?response_type=code&client_id=s6BhdRkqt3
&state=xyz
&redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb
Similarly, the Spring OAuth2 Developer Guide only contains one use of the word encode.

Seems you are looking for what is commonly called percent-encoding or URL-encoding. There are functions for this in almost every language's HTTP library, either for a single value or for a set of key-value pairs.
In practice application/x-www-form-urlencoded is almost the same as URL-encoded.

Related

Can we have two #PathVariable. One as the actual Path Variable and other for swagger to document it as Deprecated?

I am trying to change the REST call's #PathVariable. The existing Path Variable is formed by combination of three parameters. The change is to handle Path Variable formed by combination of two parameters. I need this change to be documented in swagger with the earlier shown as Deprecated.
I have tried to use both Path Variable with one as #Deprecated like below
#Parameter(description = "x_y_z - x is first ID, y is second ID, z is third ID", required=false )
#Deprecated #PathVariable String x_y_z,
#Parameter(description = "x_y - x is first ID, y is second ID", required=true )
#PathVariable String x_y)
The have changed request mapping value from /aaa/bbb/{x_y_z} to below
#RequestMapping(value = "/aaa/bbb/{x_y}", method = RequestMethod.GET, produces = "application/json"
With above changes the request fails with 500 error, may be since it is expecting two Path Variables. But the swagger documentation is as expected.
I tried to remove #PathVariable for x_y_z. The request is processed as expected and the swagger now shows x_y_z as deprecated but shows the parameter as (query) instead of (path)
Any suggestions please
Assuming an #RestController and that Swagger understands #Deprecated for a method:
#Deprecated
#GetMapping("/aaa/bbb/{x:\\d+}_{y:\\d+}_{z:\\d+}")
public ResponseEntity<MessageResponse> getStuff(#PathVariable String x,
#PathVariable String y,
#PathVariable(name = "z", required = false) String z) {
return getNewStuff(x, y); //send to the other method and ignore z
}
#GetMapping("/aaa/bbb/{x:\\d+}_{y:\\d+}")
public ResponseEntity<MessageResponse> getNewStuff(#PathVariable String x,
#PathVariable String y) {
// do stuff for x and y by default
return ResponseEntity.ok(new MessageResponse("this method is supported for " + x + " and " + y));
}
The RegEx should look for digits as the path variables, interspersed with underscores.
NB: leaving this part of the answer if Swagger works with it instead with the understanding that it could be deprecated:
#PathVariable #Parameter(description = "x_y_z - x is first ID, y is second ID, z is third ID", deprecated = true) String z
Deprecating the original method and introducing a new method with the correct parameters but different RequestMapping could also be a valid workaround.
The other part to note is that it is more common to use slashes as the delimiter rather than underscores in Spring (e.g., /aaa/bbb/x/y). You also may wish to include a validator that fits your requirements.

How to make Get Request with Request param in Postman

I have created an endpoint that accepts a string in its request param
#GetMapping(value = "/validate")
private void validateExpression(#RequestParam(value = "expression") String expression) {
System.out.println(expression);
// code to validate the input string
}
While sending the request from postman as
https://localhost:8443/validate?expression=Y07607=Curr_month:Y07606/Curr_month:Y07608
// lets say this is a valid input
console displays as
Y07607=Curr_month:Y07606/Curr_month:Y07608 Valid
But when i send
https://localhost:8443/validate?expression=Y07607=Curr_month:Y07606+Curr_month:Y07608
//which is also an valid input
console displays as
Y07607=Curr_month:Y07606 Curr_month:Y07608 Invalid
I am not understanding why "+" is not accepted as parameter.
"+" just vanishes till it reaches the api! Why?
I suggest to add this regular expression to your code to handle '+' char :
#GetMapping(value = "/validate")
private void validateExpression(#RequestParam(value = "expression:.+") String expression) {
System.out.println(expression);
// code to validate the input string
}
I didn't find any solution but the reason is because + is a special character in a URL escape for spaces. Thats why it is replacing + with a " " i.e. a space.
So apparently I have to encode it from my front-end
Its wise to encode special characters in a URL. Characters like \ or :, etc.
For + the format or value is %2. You can read more about URL encoding here. This is actually the preferred method because these special characters can sometimes cause unintended events to occur, like / or = which can mean something else in the URL.
And you need not worry about manually decoding it in the backend or server because it is automatically decoded, in most cases and frameworks. In your case, I assume you are using Spring Boot, so you don't need to worry about decoding.

Unable to pass Header Authorization in JMeter. Facing unauthorizedError

I'm running Performance test in JMeter where I have to pass Authorization details using Header Manager.
Here is my code:
String headerName = "Authorization";
String headerValue = "Basic MyKey MyValue";
Header bcHeader = new Header(headerName,headerValue);
HeaderManager hm = new HeaderManager();
hm.setProperty(TestElement.TEST_CLASS, HeaderManager.class.getName());
hm.add(bcHeader);
hm.add(new Header("Content-Type", "application/json"));
hm.add(new Header("Access-Control-Allow-Origin", "*"));
And I'm facing UnAuthorized error.
Please let me know if there is another way to write the code.
Thanks.
Normally you should be using HTTP Authorization Manager in order to bypass Basic HTTP Auth challenge.
However if you're going to manually construct Authorization header be aware that it should have the following form
Name: Authorization
Value: Basic
After Basic you need to provide username and password separated by colon and encoded into Base64. So if your username is MyKey and password is MyValue you should encode the string MyKey:MyValue and add the result to the header so it would look like:
Basic TXlLZXk6TXlWYWx1ZQ==
When it comes to Java code it would be something like:
String headerName = "Authorization";
String username = "MyKey";
String password = "MyValue";
Header bcHeader = new Header(headerName,
"Basic " +
Base64.encodeBase64String((username + ":" + password).getBytes(StandardCharsets.UTF_8)));
HeaderManager hm = new HeaderManager();
hm.add(bcHeader);
hm.add(new Header("Content-Type", "application/json"));
hm.add(new Header("Access-Control-Allow-Origin", "*"));
hm.setName(JMeterUtils.getResString("header_manager_title"));
hm.setProperty(TestElement.TEST_CLASS, HeaderManager.class.getName());
hm.setProperty(TestElement.GUI_CLASS, HeaderPanel.class.getName());
If you are getting authorization header value somewhere in your response you can extract and dynamic values and apply correlations to the script.
Here is what you have to do. Extract Authorization header value using regular expressions and store it in a jmeter variable lets assuem you have saved it as Auth .
Add a header manager (Right click on thread group -->config element--> Header manager) according to jmeter scoping rules.
Use ${variablename} and replace the hard coded header value with ${variablename} ,as we saved it in Auth variable you can use ${Auth}.
You can add headers to header manager click on add and give header name and value as shown below
i'm getting authorization value in request 1's reponse as shown below
so to extract this add a regular expression extractor to the same request (request 1) as shown below.
Now we can use ${Auth} in header manager , add header manager to request 2 and give header name and values as shown below
you can see in the results authorization has passed its value
For more information on Extracting variables please follow this link
Let me know if it helps

URL encoding using the new Spring UriComponentsBuilder

I'm attempting to use spring's UriComponentsBuilder to generate some urls for oauth interaction. The query parameters include such entities as callback urls and parameter values with spaces in them.
Attempting to use UriComponentBuilder (because UriUtils is now deprecated)
UriComponentsBuilder urlBuilder = UriComponentsBuilder.fromHttpUrl(oauthURL);
urlBuilder.queryParam("client_id", clientId);
urlBuilder.queryParam("redirect_uri", redirectURI);
urlBuilder.queryParam("scope", "test1 test2");
String url = urlBuilder.build(false).encode().toUriString();
Unfortunately, while the space in the scope parameter is successfully replaced with '+', the redirect_uri parameter is not at all url encoded.
E.g,
redirect_uri=https://oauth2-login-demo.appspot.com/code
should have ended up
redirect_uri=https%3A%2F%2Foauth2-login-demo.appspot.com%2Fcode
but was untouched. Diving into the code, specifically org.springframework.web.util.HierarchicalUriComponents.Type.QUERY_PARAM.isAllowed(c) :
if ('=' == c || '+' == c || '&' == c) {
return false;
}
else {
return isPchar(c) || '/' == c || '?' == c;
}
clearly allows ':' and '/' characters, which by gum, it shouldn't. It must be doing some other type of encoding, though for the life of me, I can't imagine what. Am I barking up the wrong tree(s) here?
Thanks
UriComponentsBuilder is encoding your URI in accordance with RFC 3986, with section 3.4 about the 'query' component of a URI being of particular note.
Within the 'query' component, the characters / and : are permitted, and do not need escaping.
To take the / character for example: the 'query' component (which is clearly delimited by unescaped ? and (optionally) # characters), is not hierarchical and the / character has no special meaning. So it doesn't need encoding.
from what I understand, UriComponentsBuilder doesn't encode the query parameters automatically, just the original HttpUrl it's instantiated with. In other words, you still have to explicitly encode:
String redirectURI= "https://oauth2-login-demo.appspot.com/code";
urlBuilder.queryParam("redirect_uri", URLEncoder.encode(redirectURI,"UTF-8" ));
Try to scan the UriComponentsBuilder doc, there is method named build(boolean encoded)
Sample code 1:
UriComponents uriComponents = UriComponentsBuilder.fromPath("/path1/path2").build(true);
Here is my sample code 2:
UriComponents uriComponents = UriComponentsBuilder.newInstance()
.scheme("https")
.host("my.host")
.path("/path1/path2").query(parameters).build(true);
URI uri= uriComponents.toUri();
ResponseEntity<MyEntityResponse> responseEntity = restTemplate.exchange(uri,
HttpMethod.GET, entity, typeRef);
I tried all the solutions above until I got it working.
In my example, I was trying to encode the ZonedDateTime format 2022-01-21T10:17:10.228+06:00. The plus sign was a problem.
What solved my issue was encoding the value manually + using URI instead of the string value (both were very important).
Before:
restTemplate.exchange(
UriComponentsBuilder
.queryParam("fromDateTime", "2022-01-21T10:17:10.228+06:00")
.build()
.toUriString(),
HttpMethod.GET,
null,
new ParameterizedTypeReference<List<MyDto>>() {}
);
After:
restTemplate.exchange(
UriComponentsBuilder
.queryParam("fromDateTime", URLEncoder.encode("2022-01-21T10:17:10.228+06:00", StandardCharsets.UTF_8))
.build(true)
.toUri(),
HttpMethod.GET,
null,
new ParameterizedTypeReference<List<MyDto>>() {}
);

Passing a filepath over url

I need to pass this filepath over via route to my actionmethod:
<p>#car.Name</p>
so for example #car.ContainerPath is a string of "34_Creating%20Cars%20Forms/Exercise%20Cars/Audi%202010%20Parts%20Reference.pdf"
I need to escape this somehow I think? I would prefer not to send this over url but with a hyperlink I don't see a way not to.
UPDATE:
For additional info, here's the actionmethod it's going to:
public string GetFileZipDownloadUrl(CarViewModel model, string fileContainerPath)
{
string downloadUrl = string.Empty;
downloadUrl = GetFileZipDownloadUrl(model.CarId,fileContainerPath, model.UserId);
return downloadUrl;
}
so I'm sending over for that fileContainerPath paths like this in the url for that #car.ContainerPath param:
"55_Creating Cars Forms/Exercise Cars/Audi Parts Reference.pdf"
so the route url before it's requested looks like this when formed in that hyperlink:
http://Cars/55/55_Creating Cars Forms/Exercise Cars/Audi Parts Reference.pdf/20/Url
My action method just needs to use that path to go get a reference to a file under the hood.
If you want to just get rid of %20 in the url use encoding/decoding like in #Xander's answer. However if any of your data is very dynamic and can have weird characters you should consider adding a Safe() and Unsafe() methods that will strip out all the "Dangerous" characters for url, and then turn it back to original value.
Raw Url:
HttpUtility.UrlEncode(rawurl);
Decode encoded url:
HttpUtility.UrlDecode(encodedurl);
http://msdn.microsoft.com/en-us/library/system.web.httputility.urlencode.aspx
http://msdn.microsoft.com/en-us/library/system.web.httputility.urldecode.aspx

Resources