I am using FreeMarker template engine to get template from external URL which requires basic authentication. For this I am setting the template loader to a URLTemplateLoader and providing my implementation of getURL() method.
configuration.setTemplateLoader(new URLTemplateLoader() {
protected URL getURL(String templateName) {
URL url = null;
url = new URL(URL where template resides);
return url;
} }
I am able to get the template in case the URL does not require authentication. But i do not see any way to provide username password for the case where URL needs authentication. Please suggest.
I was using the new URL(String path) constructor which was restricting me to provide authentication data. Instead, java.net.URL class contains a constructor which allows you to pass URLStreamHandler. I had to write my own handler which extends the handler provided by the Java/container at runtime and provide my own implementation of openConnection() method of handler class.
You need to override openConnection() method as this is the one which is used by freemarker when it tries to load the template.
Thanks.
Related
I'd like to create URLs based on the URL used by the client for the active request. Is there anything smarter than taking the current HttpServletRequest object and it's getParameter...() methods to rebuilt the complete URL including (and only) it's GET parameters.
Clarification: If possible I want to resign from using a HttpServletRequest object.
Well there are two methods to access this data easier, but the interface doesn't offer the possibility to get the whole URL with one call. You have to build it manually:
public static String makeUrl(HttpServletRequest request)
{
return request.getRequestURL().toString() + "?" + request.getQueryString();
}
I don't know about a way to do this with any Spring MVC facilities.
If you want to access the current Request without passing it everywhere you will have to add a listener in the web.xml:
<listener>
<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>
And then use this to get the request bound to the current Thread:
((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest()
Instead of using RequestContextHolder directly, you can also use ServletUriComponentsBuilder and its static methods:
ServletUriComponentsBuilder.fromCurrentContextPath()
ServletUriComponentsBuilder.fromCurrentServletMapping()
ServletUriComponentsBuilder.fromCurrentRequestUri()
ServletUriComponentsBuilder.fromCurrentRequest()
They use RequestContextHolder under the hood, but provide additional flexibility to build new URLs using the capabilities of UriComponentsBuilder.
Example:
ServletUriComponentsBuilder builder = ServletUriComponentsBuilder.fromCurrentRequestUri();
builder.scheme("https");
builder.replaceQueryParam("someBoolean", false);
URI newUri = builder.build().toUri();
Java's URI Class can help you out of this:
public static String getCurrentUrl(HttpServletRequest request){
URL url = new URL(request.getRequestURL().toString());
String host = url.getHost();
String userInfo = url.getUserInfo();
String scheme = url.getProtocol();
String port = url.getPort();
String path = request.getAttribute("javax.servlet.forward.request_uri");
String query = request.getAttribute("javax.servlet.forward.query_string");
URI uri = new URI(scheme,userInfo,host,port,path,query,null)
return uri.toString();
}
in jsp file:
request.getAttribute("javax.servlet.forward.request_uri")
You can also add a UriComponentsBuilder to the method signature of your controller method. Spring will inject an instance of the builder created from the current request.
#GetMapping
public ResponseEntity<MyResponse> doSomething(UriComponentsBuilder uriComponentsBuilder) {
URI someNewUriBasedOnCurrentRequest = uriComponentsBuilder
.replacePath(null)
.replaceQuery(null)
.pathSegment("some", "new", "path")
.build().toUri();
//...
}
Using the builder you can directly start creating URIs based on the current request e.g. modify path segments.
See also UriComponentsBuilderMethodArgumentResolver
If you need the URL till hostname and not the path use Apache's Common Lib StringUtil, and from URL extract the substring till third indexOf /.
public static String getURL(HttpServletRequest request){
String fullURL = request.getRequestURL().toString();
return fullURL.substring(0,StringUtils.ordinalIndexOf(fullURL, "/", 3));
}
Example: If fullURL is https://example.com/path/after/url/ then
Output will be https://example.com
System.out.println(((HttpServletRequest)request).getRequestURI());
I used it. hope it's useful.
I am working on a web application using Spring MVC architecture. I have a controller method that will be called by an ajax post(). The request mapper in the controller has a ".html" (meant for some cleanup task)for which the Spring Internal view resolver is trying to find a matching .JSP file and throws a 404 Not Found error. I donot want to create a .JSP which is not useful in my case. I need some help to determine if there is any setting in Spring Context xml to let the view resolver ignore this url and not to look for its .JSP file.
#RequestMapping(value = "/clearSession.html")
public void unloadDAOSession(HttpServletRequest request) {...}
the InternalViewResolver is looking for clearSession.jsp which throws a 404 Resource Not found. I dont want to create a JSP which is of no use.
Are there any application Context settings in the view resolver to ignore this ".html" file and not to look for its ".jsp"?
Any help is appreciated.
Even though the return type is void it only means that the view name will be resolved based on the URL as you have seen.
One way to avoid view resoluion is to annotate the response with #ResponseBody or
bypass the view resolver by tweaking your return type to something like
#RequestMapping(value = "/clearSession.html")
public ResponseEntity<String> unloadDAOSession(HttpServletRequest request) {
...
return new ResponseEntity<String>("OK",HttpStatus.NO_CONTENT);
}
This way instead of forwarding to a view, your just adding a header and an empty body to the response stream
In case of use of ajax and traditional controller, the best approach is write the your controller for answare to the page rendering as you had done adn then write a rest end-point layer for answare to ajax request.
I just give you some piece of code for clearing what I want say:
Controller layer:
#RequestMapping(value = "/yourPage")
public void yourPage(Model mode) {...}
Rest layer:
#RequestMapping(value = "/yourAjax")
public ResponseEntity<String> yourAjax(#RequstBody YoutDTOClass postBody) {
...
return ResponseEntity.created(...).build();
}
class YoutDTOClass{
// your properties
....
}
with this schema you separate the service layer for your ajax request and the classic web layer for serving the your page.
Just an hint don't use a pattern like /yourPage.html but you should prefare a pattern like /youtPage.This balically for banefit of the view resolver abstraction of Spring, you should let to springMVC to resolve the actual view.
Even for the ajax you should use the accept header for ask the correct rappresentation of your resource and the ResponseEntity should be used for return a 201 Http status for say to your browser that the your resource was created. remember that a better approach should prefere the use of http method in REST world and then for delete a session you should be prefare delte method for delete a session and put http method for update the sate of the session.
I hope that this can help you
I have some validation logic, which is based a user's session.
Сan I access the session from a class inherited from AbstractValidator?
Or is there another way to check RequestDTO based session?
For example I can use filters for that (and I can access the session via IRequest parameter req in overrided Execute method), but I don't know how to return the response from the class of the filter, bypassing the main method of the operation. If I will throw the Exception, the service will not work properly because RequestDTO declared outside of my project and it is not inherited from IReturn<> and does not contain a ResponseStatus field.
Thanks in advance for any help (and sorry for my English)
If your validator implements IRequiresRequest then it will injected with the current IRequest which you can use in your lambda expressions, e.g:
public class CustomValidator : AbstractValidator<Request>, IRequiresRequest
{
public IRequest Request { get; set; }
...
}
My current Spring3 REST JSON api is authenticated with the default InMemory properties file/basic-authentication authentication manager. That has worked fine thus far, but I need to further validate that an incoming request is allowed to be made for that user. The Role concept seems to work fine as a gateway for entry to a particular controller's url, but it doesn't go far enough to validate that the user is permitted to ask for the data being requested.
In my app, each B2B partner that will be making requests to the API is assigned an applicationId. That partner user account is only allowed to make requests for that applicationId. The applicationId is passed as an attribute of the RequestBody POJO for all the POST API messages. I would like to decline requests that are made for improper applicationIds.
How can I validate that the authenticated user is making a permitted request?
I've started down the path of creating a custom AuthenticationProvider, but I don't know how to get access to the applicationId within the RequestBody bean that hadn't been marshalled into the java bean yet.
Perhaps a custom AuthenticationProvider isn’t the right solution, and a request validator of some sort is needed. If so, how would the validator on the appId attribute get access to the Principal (authenticated user object)
With any solution, I would like it be invisible to the controller, so that requests that do make it to the controller are permitted ones. Also, ideally, the solution should not depend on an engineer to remember some annotation to make the logic work.
Thanks in advance,
JasonV
EDIT 1: By implementing an InitBinder in the controller, and using the #Valid annotation on the RequestBody I was able to validate a request. However, this is not the Droids (er I mean solution) I'm looking for. I need to find a more generic way to handle it without all those Binders and annotations; too much to remember and spread around the application over dozens of request controllers, and it will be forgotten in the future.
The usual way to implement this is using #PreAuthorize.
#PreAuthorize("hasRole('USER') and authentication.principal.approvedAppId == #dto.applicationId")
#RequestMapping...
public ... someMethod(#RequestBody Dto dto, ...)
If you're worried about the repetition of the SpEL, define a new annotation like #PreAuthorizeUser and set the #PreAuthorize as a meta-annotation on it.
I was able to utilize an aspect to solve the problem generically.
I would still like to see if it is possible to do the following:
Get a marshalled RequestBody from the request object in the context of an AuthenticationProvider.
Here is the aspect code for future help to others.
#Pointcut("within(#org.springframework.stereotype.Controller *)")
public void controllerBean() {
}
#Pointcut(
"execution(org.springframework.http.ResponseEntity *(.., #org.springframework.web.bind.annotation.RequestBody (*),..))")
public void methodPointcut() {
}
#Around("controllerBean() && methodPointcut()")
public Object beforeMethodInControllerClass(ProceedingJoinPoint jp) throws Throwable {
Object[] args = jp.getArgs();
long requestAppId = Long.parseLong(BeanUtils.getProperty(args[0], "applicationId"));
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
User principal = (User) auth.getPrincipal();
String username = principal.getUsername();
long[] approvedAppIds = getApprovedAppIdsForUsername(username);
for (long approvedAppId : approvedAppIds) {
if (approvedAppId == requestAppId) {
isAllowedAccess = true;
break;
}
}
if (isAllowedAccess) {
return jp.proceed(args);
} else {
LOGGER.warn("There was an attempt by a user to access an appId they are not approved to access: username="+username+", attempted appId="+requestAppId);
return new ResponseEntity(HttpStatus.FORBIDDEN);
}
}
I am building a webservices application using jersey,jax-rs
I have single jax-rs resource file at path "/authenticate"
I have multiple methods with individual paths like "/user" "/test"
#Path ("/authenticate")
public class Authenticate{
private static final Log log = LogFactory.getLog(Authenticate.class);
#QueryParam("entityId")
String entity;
#GET
#Path ("/{param}")
public Response getMsg(#PathParam ("param") String msg) {
String o = "Hello Welcome Back:"+msg;
return Response.status(200).entity(o).build();
}
#GET
#Path ("/user")
#Produces({"application/json"})
public UserDTO getUser (#Context HttpServletRequest request,
#QueryParam("userId") int userId) {
System.out.println("In Get User, User:"+userId);
System.out.println("In Get User, Entity:"+entity);
}
#GET
#Path ("/test")
#Produces({"application/json"})
public TestPOJO getTestPOJO () {
System.out.println("In Get TestPOJO");
System.out.println("In Get Test, Entity:"+entity);
return new TestPOJO();
}
}
As suggested for jersey client, I am using a single webresource from client and build subsequent webresources from the same webresource by using .path("/xxx").
Here is how I create the initial web resource
WebResource webResource = client.resource("http://localhost:8080/Service/jaxrs/authenticate");
webResource.queryParam("entityId", securityHelper.getEntityId().toString());
Here is how I use the webresource subsequently
MultivaluedMap<String, String> params = new MultivaluedMapImpl();
ClientResponse userRes = webResource.path("/user").queryParams(params).accept("application/json").get(ClientResponse.class);
I want to assign a queryparam to the initial webresource, and I want that to be retained by all subsequent webresources created using the .path(). But that is not happening right now. For example in the above code "entityId" is not available when the call with path("/user") is made.
My idea is to assign common parameters once and all subsequent users of the webResource need not add those again and again. Is there a way to do it? Will this approach work?
The line below creates a new WebResource and not changing the state of the webResource object:
webResource.queryParam("entityId", securityHelper.getEntityId().toString())
Eventually you could change your code like this to create the "base" resource:
WebResource webResource = client.resource("http://localhost:8080/Service/jaxrs/authenticate").queryParam("entityId", securityHelper.getEntityId().toString());
And then use this resource to create another resources as you like. WebResource.queryParam and WebResource.queryParams always create a new WebResource object.
I'm may not be the best person to answer this since I have entered the "world" of Jersey and RESTful servers not too long ago but since i saw this unanswered for 2 days ill try to help out as best as I can.
If i understood correctly you are trying to, by using a query, save the user information on entityId String so it will be available when you make a subsequent call.
Ok let's start with what you have. With your code (entityId as a global parameter), what you are specifying , is that when you are calling a resource from the Authenticate class, any call can be made with a query of the type '?entityId="something" and ANY method in this class can use the information sent in the query.
The thing is, for what I've learned by messing about with Jersey, whenever you make a call, the resource class (in your case Authenticate) is instantiated again. Therefor you can't just keep information in a global parameter since subsequent calls will have the String entityId as null.
This means that if you want to save the information you'll have to do it in a external resource (ex: db, file, etc). What method you choose depends on what you want to do and what are you looking for in your application.
I hope I was at least able to shed a sliver of light on your problem.