regexMatcher for URL with query parameters in Spring Security - spring

How should I use parameters like this in regexMatcher in Spring Security? I have many URLs that start with /sUrl and have different parameters. This code doesn't work!
.regexMatchers("\\/sUrl\\?params=\\{url:\"reports\\/Manager\",subSystem:\"ABS\"\\}").access("hasRole('ROLE_ABS')")
Controller:
#RequestMapping(value = "sUrl", method = RequestMethod.GET)
public RedirectView sUrl(#RequestParam(name = "params") String params) {
RedirectView redirectView = new RedirectView();
.
.
.
return redirectView;
}
URL seen in network partition of browser inspector when I click on this link:
sUrl?params={url:%22reports/Manager%22,subSystem:%22ABS%22}

You have to use a regular expression with the URL-encoded query parameter, see RegexRequestMatcher:
Uses a regular expression to decide whether a supplied the URL of a supplied HttpServletRequest. Can also be configured to match a specific HTTP method. The match is performed against the servletPath + pathInfo + queryString of the request and is case-sensitive by default. Case-insensitive matching can be used by using the constructor which takes the caseInsensitive argument.
and HttpServletRequest:
Returns the query string that is contained in the request URL after the path. This method returns null if the URL does not have a query string. Same as the value of the CGI variable QUERY_STRING.
Returns:
a String containing the query string or null if the URL contains no query string. The value is not decoded by the container.
Your modfified code:
.regexMatchers("\\/sUrl\\?params=\\{url:%22reports\\/Manager\%22,subSystem:%22ABS%22\\}").access("hasRole('ROLE_ABS')")

Related

'/' is added to my redirect URL when I try to pass query params

I have a spring app that has a controller to redirect the user to a specific URL based on data they send me. If the data is wrong, I direct them to a url with an error code and description. However, when I do this redirect, it is adding a / before the query parameters, making the redirection wrong. So the code would look like:
Controller.class
String Failure_URL="https://www.google.com";
if(response.getStatus()!=200) {
//there was an error, so redirect to error URL
//map response to my object class
MyObject obj = new MyObject(response);
String redirectURL = Failure_URL + "?error_code=" + obj.getError_Code()
+ "&description=" + obj.getDescription();
}
return new ModelAndView("redirect:" + redirectURL);
When I look at my network trace during testing, I can see the Location header is being set correctly. https://www.google.com?error_code=001&description=System+Error, however when it makes the redirect the URL turns into https://www.google.com/?error_code=SECB001&description=System+Error, making those queryparams a path URI. Is there any way to stop it from doing this, it means these values aren't being set as params correctly. Is this due to the + in the description, and should I encode it?
You should use Spring's UriComponentsBuilder to build URL programmatically and avoid such weird behaviours.
You can build URL like below:
String Failure_URL = UriComponentsBuilder.newInstance()
.scheme("https")
.host("www.google.com")
.queryParam("error_code", "error_code_value")
.queryParam("description", "description_value")
.build().toUriString();
In case you need to add / in URL, you can add .path("/") wherever it is required.

How to get Swagger UI to display similar Spring Boot REST endpoints?

I have a controller class with two endpoints
#RestController
#RequestMapping
public class TestController {
#RequestMapping(
value= "/test",
method = RequestMethod.GET)
#ResponseBody
public String getTest() {
return "test without params";
}
#RequestMapping(
value= "/test",
params = {"param"},
method = RequestMethod.GET)
#ResponseBody
public String getTest(#PathParam("param") int param) {
return "test with param";
}
}
One has a parameter, one doesn't, and the both work.
If I use curl or a web browser to hit the endpoints
http://localhost:8081/test
returns
test without params
and
http://localhost:8081/test?param=1
returns
test with param
but the swagger ui only shows the one without a parameter.
If I change the value in the request mapping for the request with a parameter to
#RequestMapping(
value= "/testbyparam",
params = {"param"},
method = RequestMethod.GET)
Swagger UI displays both endpoints correctly, but I'd rather not define my endpoints based on what swagger will or won't display.
Is there any way for me to get swagger ui to properly display endpoints with matching values, but different parameters?
Edit for Clarification:
The endpoints work perfectly fine; /test and /test?param=1 both work perfectly, the issue is that swagger-ui won't display them.
I would like for swagger ui to display the endpoints I have defined, but if it can't, then I'll just have to live with swagger-ui missing some of my endpoints.
Edit with reference:
The people answering here: Proper REST formatted URL with date ranges
explicitly say not to seperate the query string with a slash
They also said "There shouldn't be a slash before the query string."
The issue is in your Request Mapping, The second method declaration is overriding the first method. As Resource Mapping value is same.
Try changing the second method to below. As you want to give input in QueryParam rather than path variable, you should use #RequestParam not #PathParam.
Note that you have to give /test/, In order to tell Spring that your mapping is not ambiguous. Hope it helps.
#RequestMapping(
value= "/test/",
method = RequestMethod.GET)
#ResponseBody
public String getTest (#RequestParam("param") int param) {
return "test with param"+param;
}
Upon reading clarifications, the issue here is that swagger-ui is doing the correct thing.
You have two controller endpoints, but they are for the same RESOURCE /test that takes a set of optional query parameters.
Effectively, all mapped controller endpoints that have the same method (GET) and request mapping (/test) represent a single logical resource. GET operation on the test resource, and a set of optional parameters which may affect the results of invoking that operation.
The fact that you've implemented this as two separate controller endpoints is an implementation detail and does not change the fact that there is a single /test resource that can be operated upon.
What would be the benefit to consumers of your API by listing this as two separate endpoints in swagger UI vs a single endpoint with optional parameters? Perhaps it could constrain the set of allowed valid query parameters (if you set ?foo you MUST set &bar) but this can also be done in descriptive text, and is a much more standard approach. Personally, I am unfamiliar with any publicly documented api that distinguishes multiple operations for the same resource differentiated by query params.
As per Open API Specification 3
OpenAPI defines a unique operation as a combination of a path and an
HTTP method. This means that two GET or two POST methods for the same
path are not allowed – even if they have different parameters
(parameters have no effect on uniqueness).
Reference - https://swagger.io/docs/specification/paths-and-operations/
This was also raised as an issue but it was closed because OAS3 doesn't allow that -
https://github.com/springdoc/springdoc-openapi/issues/859
Try including the param in the path as below.
#GetMapping("/test/{param}")
public String getTest(#PathVariable final int param) {
return "test with param";
}
I'm unclear exactly what you're attempting to do, but I'll give two solutions:
If you want to have PATH parameters e.g. GET /test & GET /test/123 you can do:
#GetMapping("/test")
public String getTest() {
return "test without params";
}
#GetMapping("test/{param}")
public String getTest(#PathVariable("param") int param) {
return "test with param";
}
If you want query parameters (GET /test and GET /test?param=123) then you need a single endpoint that takes an optional parameter:
#GetMapping("test")
public String getTest(#RequestParam("param") Integer param) {
if(param == null) {
return "test without params";
} else {
return "test with param";
}
}

Spring Rest Service GET with parentheses

I have a Spring Rest Service like this:
#RequestMapping(value = "/banks", method = RequestMethod.GET)
public List<String> getBanks( #RequestParam(value="name" , required=true) String name) {
...
}
The name must allows special character like parentheses, but the problem is that when i put parentheses on the param, y receive the ASCCI code like #040# on the "name" parameter.
I thought in use #RequestBody with a wrap filter like a posible solution, but the method must change to POST to support the wrap in the Request Body and the api design going to be bad.
So, someone have a solition for support parentheses on the param of a GET Rest Service?

Net Web API - How to pass a URL as input parameter on a Get

I am trying to pass a URL as a input parameter to a ApiController from an Angular REST call. The URL comes as a query string (this is a Provider Hosted app in SharePoint, I need the URL to query SP FWIW).
Here is the method signature in the ApiController:
// GET: api/ProjectSite/5
public IEnumerable<ProjectSite> Get(string id)
{
return ProjectSite.GetAllProjectSites(id);
}
And here is where I am making the call in Angular:
var spUrl = "'" + getParameterByName("SPHostUrl") + "'";
var queryUrl = "/api/ProjectSite/" + encodeURIComponent(spUrl);
return $http.get(queryUrl);
This generates a GET request that looks like this:
https://localhost:12345/api/ProjectSite/https%3A%2F%2Fcompany.sharepoint.com%2Fsites%2Fsite_dev%2Fweb
When I do I get 'HTTP 400 (Bad Request)' back. If I stop on a break point in the Angular code and change the input param to a simple string (e.g. 'asdf') the REST call is made and I see the Api is called. If I do not change the string and put a breakpoint inside the Get Api method the breakpoint is not reached, indicating that the code is blowing up somewhere in the route engine.
What I don't get is, while its encoded, the string I am trying to pass in should still be treated as a string, right? I also tried changing the input to Uri but that doesn't appear to work (and Uri isn't listed as a supported input type, anyways).
Anyone know how to pass a URL as input parameter?
Have you tried calling it using a query string?
var queryUrl = "/api/ProjectSite?id=" + encodeURIComponent(spUrl);

Pass URL containing a query string as a parameter ASP.Net Web API GET?

I'm trying to pass in an URL as a string parameter to a WEB API GET method.
The controller:
public class LinksController : ApiController
{
public HttpResponseMessage Get(string targetUrl)
{
//query db with targetURL
}
}
The aim is to query the database to see if the URL is stored. This works fine with simple URLs and URLs whose query string contains a single parameter, like:
http://www.youtube.com/watch?v=nLPE4vhSBx4
The problem I'm encountering is specifically when the query string contains multiple parameters, e.g.
http://www.youtube.com/watch?v=nLPE4vhSBx4&feature=youtube_gdata
When debugging, the value of targetUrl is only ".../watch?v=nLPE4vhSBx4" which means &feature=youtube_gdata is lost.
The GET request looks like this:
http://localhost:58056/api/links?targetUrl=http://www.youtube.com/watch? v=nLPE4vhSBx4&feature=youtube_gdata
I've also tried to add the following route in WebApiConfig.cs:
config.Routes.MapHttpRoute(
name: "Links",
routeTemplate: "api/links/{targetUrl}",
defaults: new { controller = "Links", targetUrl= RouteParameter.Optional }
);
But the GET request then results in 400 Bad Request.
So my question is, can't this be done? I would like the complete URL! Or would I need to change the method header to use the [FromBody] attribute and pass it as a JSON object?
You should URLEncode your target URL parameter so that it doesn't get mistaken for subsequent query string parameter. This means the URL you specified should appear as:
http://localhost:58056/api/links?targetUrl=http%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DnLPE4vhSBx4%26feature%3Dyoutube_gdata
And then inside your Get method, URLDecode the string that is passed as a parameter.
Both methods can be found in System.Web.HttpUtility

Resources