I have a jax-rs endpoint. The purpose of the endpoint is to authorize a user. I need to login details inside a cookie. Below I have mentioned the related part of my code.
public Response authorize(#Context HttpServletRequest request) throws URISyntaxException {
if (authnResult.isAuthenticated()) {
//TODO create a cookie to maintain login state
Cookie authCookie = new Cookie(FrameworkConstants.COMMONAUTH_COOKIE, "test");
authCookie.setSecure(true);
authCookie.setHttpOnly(false);
authCookie.setMaxAge(5 * 60);
}
EDIT:
This is my first time when creating cookies. I followed some tutorials. In these tutorials it has added the created cookie to the response. But inside the endpoint I can't access the response. So how can I create the cookie? Please advice me.
Updated code:
public Response authorize(#Context HttpServletRequest request) throws URISyntaxException {
NewCookie cookie = new NewCookie("CookieName","CookieValue");
Response.ResponseBuilder builder = Response.ok("Cool Stuff");
builder.cookie(cookie);
Response response=builder.build();
Cookie[] cookies = request.getCookies();
}
what I need to know is how to access the newly created cookie.
You can create a javax.ws.rs.core.NewCookie. There are a bunch of different constructors, just go through the API docs.
Then you can add cookies through ResponseBuilder#cookie(NewCookie). So for example:
#GET
public Response getCookie() {
NewCookie cookie = new NewCookie("Name", "Value", "path", "domain",
"comment", 300, true, true);
ResponseBuilder builder = Response.ok("Cool Stuff");
builder.cookie(cookie);
return builder.build();
}
UPDATE (with complete example)
#Path("cookie")
public class CookieResource {
#GET
public Response getCookie(#CookieParam("A-Cookie") String cookie) {
Response response = null;
if (cookie == null) {
response = Response.ok("A-Cookie: Cookie #1")
.cookie(new NewCookie("A-Cookie", "Cookie #1"))
.build();
return response;
} else {
String cookieNum = cookie.substring(cookie.indexOf("#") + 1);
int number = Integer.parseInt(cookieNum);
number++;
String updatedCookie = "Cookie #" + number;
response = Response.ok("A-Cookie: " + updatedCookie)
.cookie(new NewCookie("A-Cookie", updatedCookie))
.build();
return response;
}
}
}
After 38 requests, you can see the result. I used a Firefox plugin Firebug. You can see the sent cookie #37, and returned cookie #38
If you need help trying to access the cookie from the client (as suggested in your comment), that may be suitable for another question on SO. Maybe off topic for this discussion, as it will rely on another technology. If this is not what you are looking for, then maybe a better explanation of exactly what you are trying to accomplish would help.
Related
I am testing an application written with Java and Spring Boot and I have a question.
My test simulates an HTTP request which is valid only if the customData data is placed inside the Cookie header.
This is the code for my simple test:
#Test
public void myFristTest() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.post(MY_URL)
.header("Cookie", "customData=customString")
.accept(MediaType.APPLICATION_JSON_VALUE)
.contentType(MediaType.APPLICATION_JSON_VALUE)
.content(ConversionUtil.objectToString(BODY_OF_MY_REQUEST)))
.andExpect(status().isCreated());
}
Unfortunately this test fails. The Java code that goes to test is the following:
String customData;
Cookie[] cookies = request.getCookies();
if (cookies != null) {
for (Cookie cookie : cookies) {
if (cookie.getName().equals("customData")) {
customData = cookie.getValue();
}
}
}
if(customData != null) {
// code that returns HTTP status isCreated
} else {
throw new HttpServerErrorException(HttpStatus.FOUND, "Error 302");
}
In practice, it seems that the customData string, which should be taken from the request header Cookie, is not found! So the test only evaluates the else branch and actually also in the stacktrace tells me that the test was expecting the status isCreated but the status 302 is given.
How can this be explained, since the application (without test) works? I imagine that .header("Cookie", "customData=customString") in my test doesn't do what I want, that is, it doesn't set the header cookie correctly, which is why my method fails. How do I do a proper test that really inserts Cookie header into the request?
I use Junit 4.
The MockHttpServletRequestBuilder class provides the cookie builder method to add cookies. The MockHttpServletRequest created internally for the test ignores "Cookie" headers added through the header method.
So create a Cookie and add it
Cookie cookie = new Cookie("customData", "customString");
mockMvc.perform(MockMvcRequestBuilders.post(MY_URL)
.cookie(cookie)
.accept(MediaType.APPLICATION_JSON_VALUE)
.contentType(MediaType.APPLICATION_JSON_VALUE)
.content(ConversionUtil.objectToString(BODY_OF_MY_REQUEST)))
.andExpect(status().isCreated());
I have a requirement to make a post-call to a URL which has OAuth 1.0 authentication. I am pretty new to all these. From my research, I got to know about Scribe in Java, but I can find only Get calls using Scribe. I already have consumerKey and consumerSecret key for OAuth 1.0 authentication. Are there any suggestions on how to achieve this successfully.
With postman I am able to fetch the data successfully, but I want to achieve it using Java.
I have tried something like this
I tried this way
public String getSmartCommPDF(#RequestBody Model model) throws IOException {
OAuthService service = new ServiceBuilder().provider(ModelAPI.class).apiKey(consumerKey)
.apiSecret(consumerSecret).build();
OAuthRequest request = new OAuthRequest(Verb.POST, url);
ObjectMapper mapper = new ObjectMapper();
request.addHeader("Content-Type", "application/json;charset=UTF-8");
request.addPayload(mapper.writeValueAsString(model));
Token accessToken = new Token("", ""); // not required for context.io
service.signRequest(accessToken, request);
Response response = request.send();
System.out.println("Response = " + response.getBody());
return "Success";
}
This is my ModelAPI class
public class ModelAPI extends DefaultApi10a {
#Override
public String getRequestTokenEndpoint() {
return "https://domain/one/oauth1/api/v6/job";
}
#Override
public String getAccessTokenEndpoint() {
return "https://domain/one/oauth1/api/v6/job";
}
#Override
public String getAuthorizationUrl(Token requestToken) {
return "https://domain/one/oauth1/api/v6/job";
}
}
This part of code is not throwing any error but, the response body is empty. Where I am going wrong, any one has any idea?
Thank you.
The data was coming back in the input stream. So, I used
response.getStream();
and write it to a file and use it.
I am working on a Java desktop application and after some search I was able to authenticate the user using RestTemplate. Now the situation is I have the cookie String at the desktop side(code given below). Now what I would like to do is to do two important things, get which user logged in using that cookie and access(GET,POST,DELETE) secured resources which are marked with #Secured or #PreAuthorize annotation.
here is my authentication code :
#Override
public void initialize(URL location, ResourceBundle resources) {
submitButton.setOnAction(event -> {
if(!(usernameField.getText().isEmpty() && passwordField.getText().isEmpty())){
try {
RestTemplate rest = new RestTemplate();
String jsessionid = rest.execute("http://localhost:8080/j_spring_security_check", HttpMethod.POST,
new RequestCallback() {
#Override
public void doWithRequest(ClientHttpRequest request) throws IOException {
request.getBody().write(("j_username=" + usernameField.getText() + "&j_password=" + passwordField.getText()).getBytes());
}
}, new ResponseExtractor<String>() {
#Override
public String extractData(ClientHttpResponse response) throws IOException {
List<String> cookies = response.getHeaders().get("Cookie");
// assuming only one cookie with jsessionid as the only value
if (cookies == null) {
cookies = response.getHeaders().get("Set-Cookie");
}
String cookie = cookies.get(cookies.size() - 1);
System.out.println("Cookie is "+cookie);
int start = cookie.indexOf('=');
int end = cookie.indexOf(';');
return cookie.substring(start + 1, end);
}
});
// rest.put("http://localhost:8080/rest/program.json;jsessionid=" + jsessionid, new DAO("REST Test").asJSON());
} catch (AuthenticationException e) {
System.out.println("AuthenticationException");
}
} else {
System.out.println("Fields are empty");
}
});
}
Output of program is :
DEBUG: org.springframework.web.client.RestTemplate - Created POST request for "http://localhost:8080/j_spring_security_check"
DEBUG: org.springframework.web.client.RestTemplate - POST request for "http://localhost:8080/j_spring_security_check" resulted in 302 (Found)
Cookie is JSESSIONID=903B2924CCC84421931D52A4F0AA3C7E; Path=/; HttpOnly
If I was on server-side, I would have simply called the below method to get the currently authenticated user :
#Override
public Person getCurrentlyAuthenticatedUser() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication == null) {
return null;
} else {
return personDAO.findPersonByUsername(authentication.getName());
}
}
How can I get the currently authenticate user on desktop based java app so I can just use below method and authenticate on desktop java app. :
Collection<GrantedAuthority> authorities = new ArrayList<>();
authorities.add(new SimpleGrantedAuthority("ROLE_USER"));
Authentication authentication = new UsernamePasswordAuthenticationToken(person1, null, authorities);
SecurityContextHolder.getContext().setAuthentication(authentication);
This way, I can use #Secured annotations for the desktop java app as well. Thanks a lot.
Update
So on the server side I have created a method which gives me the logged in user. As suggested in an answer, I can use the same rest template, but I would like to store the cookie in users local db instead of passing the Resttemplates object around when user clicks here and there.
Server side method :
#Secured("ROLE_USER")
#RequestMapping(value = "/rest/getloggedinuser", method = RequestMethod.GET)
public
#ResponseBody
ResponseEntity<RestPerson> getLoggedInRestUser() {
Person person = this.personService.getCurrentlyAuthenticatedUser();
RestPerson restPerson = new RestPerson();
restPerson.setFirstname(person.getFirstName());
restPerson.setUsername(person.getUsername());
restPerson.setPassword("PROTECTED");
return new ResponseEntity<RestPerson>(restPerson, HttpStatus.OK);
}
Now, next for now, I am trying to use the same RestTemplate to check if this method works with code below, but I would really like to know how I can do this with just a cookie :
HttpHeaders requestHeaders = new HttpHeaders();
requestHeaders.add("Cookie", cookie);
HttpEntity requestEntity = new HttpEntity(null, requestHeaders);
ResponseEntity rssResponse = rest.exchange(
"/rest/getloggedinuser",
HttpMethod.GET,
requestEntity,
Person.class);
String rssResponseBody = (String)rssResponse.getBody();
System.out.println("Response body is ");
Is there a way to cast the Object in the ResponseBody to the Person object???
If you want to get some user information which is stored on the server-side, you should create a new service, for example "getUserInformation" on your server, which will provide such information.
You should not extract cookies manually, just reuse the same RestTemplate, it stores cookies internally (specifically in the underlying HttpClient). That's how you can reach secure resources.
UPDATE:
You don't need to pass around the RestTemplate, just make it a singleton and use it everywhere.
And rssResponse.getBody(); should return you a Person object, not String.
I have a scenario where I want to store session information across multiple sessions in Application # 2. We have two applications deployed on a tomcat server. Our use case is as follows:
A. Web Application # 1 makes a HTTP Post request to Application # 2 using a HTTP Rest Client. POST request contains a JSON http request body encapsulating the data to be send to Application # 2. The code block is as follows:
RestTemplate template = new RestTemplate();
final SearchCustomer customer = new SearchCustomer();
restTemplate.execute(
SEND_CUSTOMER_PROFILE, HttpMethod.POST,
new SearchRequestCallback(searchCustomer), null);
The request callback function is
static class SearchRequestCallback implements RequestCallback {
/**
* Write a JSON response to the request body.
*/
#Override
public void doWithRequest(ClientHttpRequest request) throws IOException {
HttpHeaders httpHeaders = request.getHeaders();
List<MediaType> acceptableMediaTypes = new LinkedList<>();
acceptableMediaTypes.add(MediaType.APPLICATION_JSON);
httpHeaders.setAccept(acceptableMediaTypes);
httpHeaders.setContentType(MediaType.APPLICATION_JSON);
request.getBody().write(
new Gson().toJson(this.searchCustomer).getBytes(StandardCharsets.UTF_8.displayName()));
}
}
The second application has a Spring controller with the following set up
#Controller
public class SearchCustomerController {
/**
* Builds customer profile knowledge graph.
*
* <p>This is invoked as an synchronous request.
*/
#RequestMapping(value="/searchProfilePayload.go", method=RequestMethod.POST)
#ResponseStatus(HttpStatus.OK)
public void constructSearchCustomerProfileKnowledgeGraph(
#RequestBody final SearchCustomer customer, HttpServletRequest request) {
UserContext userContext =
(UserContext) request.getSession().getAttribute("userContext");
if (userContext == null) {
// Perform heavy operation to fetch user session.
userContext = UserContextHelper.getUserContext(request);
request.getSession("userContext", userContext)
}
userContext.setCustomerProfile(customer);
}
}
When I make a call to another URI within the application # 2 say via browser, I want it done in such as way that the session attributes are retained when making this call. Is there a way to do that?
I know about URL rewriting that stores JSESSIONIDin the cookie, but I don't think how you can set the value when making a rest call, and using the same JESSIONID to maintain session attributes.
Is there a better way to do this? These have no answers. I have looked at these links, but none seem to answer my question.
HTTP and Sessions
comparison of ways to maintain state
jraahhali is spot on.
Set the cookie header with the value of JSESSIONID=${sessionId} or use it directly in the url as per the URL rewriting link.
First step is to retrieve the JSESSIONID from the initial response (this will depend on how you decide to set the session id - URL or Cookies, lets assume by cookie for now)
#Override
public void doWithRequest(ClientHttpRequest request) throws IOException {
HttpHeaders httpHeaders = request.getHeaders();
List<MediaType> acceptableMediaTypes = new LinkedList<>();
acceptableMediaTypes.add(MediaType.APPLICATION_JSON);
httpHeaders.setAccept(acceptableMediaTypes);
httpHeaders.setContentType(MediaType.APPLICATION_JSON);
request.getBody().write(
new Gson().toJson(this.searchCustomer).getBytes(StandardCharsets.UTF_8.displayName()));
ClientHttpResponse response = request.execute();
String sessionId = response.getHeaders().get(HttpHeaders.SET_COOKIE).split(":")[1].trim(); // I didnt test this, will prolly get a NPE :P
this.sessionId = sessionId;
}
Then in subsequent requests (ie from the app #1 or a browser or whatever)
if (this.sessionId != null && !this.sessionId.equals(""))
httpHeaders.set(HttpHeaders.COOKIE, "JSESSIONID=" + this.sessionId);
// ...
request.execute();
Note if you really want to use a browser as the other client then I would use the URL rewriting method for ease of use ...
I have developed a custom tag library in Java which I use in my web application.
I am not sure why but my doTag() is not setting up cookie at all. I have cleared my cache and restarted my computer as well. Here is the code:
public class UserVersionOfSite extends EvenSimplerTagSupport {
private static final Log logger = LogFactory.getLog(UserVersionOfSite.class);
private StringWriter sw = new StringWriter();
#Override
public void doTag() throws IOException, JspException {
getJspBody().invoke(sw); //get the tag body and put it in StringWriter object
//get request object to get cookie value
PageContext ctx = (PageContext)getJspContext();
HttpServletRequest httpServletRequest = (HttpServletRequest) ctx.getRequest();
HttpServletResponse httpServletResponse = (HttpServletResponse) ctx.getResponse();
if(httpServletRequest.getParameterMap().containsKey("show_full_site")) {
logger.debug("show_full_site ");
if(!checkIfCookieExists(httpServletRequest)){
Cookie cookie = new Cookie("SHOW_FULL_SITE",httpServletRequest.getParameter("show_full_site"));
cookie.setMaxAge(86400);
httpServletResponse.addCookie(cookie);
//write the tag output
if(!httpServletRequest.getParameter("show_full_site").equalsIgnoreCase("true")){
//write the response
getJspContext().getOut().println(sw.toString());
}
}else{
String cookieValueString = getCookieValue(httpServletRequest.getCookies(),"SHOW_FULL_SITE","false");
if(!cookieValueString.equalsIgnoreCase("true")){
//write the response
getJspContext().getOut().println(sw.toString());
}
}
}
}
#Override
public String getResult() throws IOException {
return "User version of site";
}
public String getCookieValue(Cookie[] cookies,
String cookieName,
String defaultValue) {
for(int i=0; i<cookies.length; i++) {
Cookie cookie = cookies[i];
if (cookieName.equals(cookie.getName()))
return(cookie.getValue());
}
return(defaultValue);
}
public boolean checkIfCookieExists(HttpServletRequest httpServletRequest){
logger.debug("inside checkIfCookieExists()");
boolean cookiePresent = Arrays.asList(httpServletRequest.getCookies()).contains( "SHOW_FULL_SITE" );
return cookiePresent;
}
}
Even I tried adding the code without using if else statements but still no success. Is there any thing critical I am missing?
Any ideas guys??!!! I have checked the browser's setting as well, but there is nothing there which is blocking a creation of cookie!
I realise the horse has probably bolted by the time I'm posting this but, for the benefit of others stumbling across it, I think the problem may be related to the feature of RequestDispatcher highlighted in this question: unable to add a cookie included in JSP via jsp:include
your following line inside checkIfCookieExists() method is wrong:
Arrays.asList(httpServletRequest.getCookies()).contains( "SHOW_FULL_SITE" );
HttpServletRequest.getCookies() returns Cookie[]. You are wrapping it inside a List and checking for a string "SHOW_FULL_SITE" inside this.
Coming back to your question- how do you know cookie is not being set in the HTTP headers? Try using browser plugins like firebug to see the HTTP response headers coming from server. Also set the path of cookie before adding it to response e.g.
Cookie cookie = new Cookie("SHOW_FULL_SITE",httpServletRequest.getParameter("show_full_site"));
cookie.setMaxAge(86400);
cookie.setPath("/");