In Spring I set some cookies I need for my websocket:
Cookie ck = new Cookie("session", request.getSession().getId());
ck.setDomain(".mydomain.com");
ck.setPath("/");
ck.setVersion(1);
Cookie secretCookie = new Cookie("scrt", secret);
secretCookie.setDomain(".mydomain.com");
secretCookie.setPath("/");
secretCookie.setVersion(1);
response.addCookie(secretCookie);
response.addCookie(ck);
But when I read the header of the websocket handshake, the value of the cookie field only consists of a string which looks like this:
session=foobar; scrt=foomart
When you try to parse this value by HttpCookie.parse(); the HTTPCookie will try to identify the version of the cookie.
private static int guessCookieVersion(String header) {
int version = 0;
header = header.toLowerCase();
if (header.indexOf("expires=") != -1) {
// only netscape cookie using 'expires'
version = 0;
} else if (header.indexOf("version=") != -1) {
// version is mandatory for rfc 2965/2109 cookie
version = 1;
} else if (header.indexOf("max-age") != -1) {
// rfc 2965/2109 use 'max-age'
version = 1;
} else if (startsWithIgnoreCase(header, SET_COOKIE2)) {
// only rfc 2965 cookie starts with 'set-cookie2'
version = 1;
}
return version;
}
If the Value is 0, which is wrong but the case here, the HttpCookie will only parse the first entry.
If you force version to be 1, this won't work either, since HttpCookie is expecting comma seperated values. splitMultiCookies(String header)
Is there any way to fix this but writing my own parser?
It is funny because a cookie has no field "version" anymore. I can find a reference to it in the RFC2109 (1997), but it is not there anymore in RFC6265 (2011). Actually, the cookie API in .NET does not provide a built-in method to set such property (that is the reason this caught my attention). Check that the browser is actually sending that data as part of the handshake, maybe the browser is ignoring it.
Related
Currently using Java I am able to create a cookie and later retrieve it via Cookie[] browserCookies = request.getCookies();
The issue comes when I try create a cookie and set its path with cookie.setPath("/"); I can no longer find it later when the below code. It has a max age of 30 days so I know it's there and I see it get created but I can't find it any longer after that initial creation.
Here's what I have now which works when not setting a path to "/":
Look for a cookie with a specific name:
Cookie[] browserCookies = request.getCookies();
boolean foundCookie = false;
if (browserCookies != null) {
for (int i =0; i< browserCookies.length; i++) {
if ("foo".equalsIgnoreCase(browserCookies[i].getName())) {
foundCookie = true;
}
}
}
based on foundCookie, I do something but also based on that I create a new cookie if not found:
if (!foundCookie) {
Cookie fooCookie = new Cookie ("foo", "barValue");
fooCookie.setMaxAge(30 * 86400);
//fooCookie.setPath("/"); // If I set this, I can no longer find it later by the name
response.addCookie(fooCookie);
}
Thank you for any help
A mail server returns this error when I send mail with several recipients :
Remote Server returned 'mx.spamexperts.com #5.0.0 smtp; 550 Messages should have one or no To headers, not 5.'
It happens when I use addRecipient method of JavaMail multiple times. If I use setRecipient instead with an array of email address, it works.
This is the consequence of the addHeader method in javax.mail.internet.InternetHeaders class. Here is the piece of code which is the cause of this issue :
for (int i = headers.size() - 1; i >= 0; i--) {
InternetHeader h = (InternetHeader)headers.get(i);
if (name.equalsIgnoreCase(h.getName())) {
if (addReverse) {
pos = i;
} else {
headers.add(i + 1, new InternetHeader(name, value));
return;
}
}
// marker for default place to add new headers
if (h.getName().equals(":"))
pos = i;
}
What do you think about that ? Why JavaMail adds new To header each time we use addRecipient if some mail server does not accept it ?
You must be using a very old version of JavaMail. This was fixed in JavaMail 1.4.4, over 5 years ago. The current version is 1.5.5.
I am sending cookie from a client in Rest API request and I want to read on a filter. I am using this code on the filter for retrieving the cookies.
Map<String, Cookie> cookies = requestContext.getCookies();
Cookie cookie = cookies.get("token");
String token = cookie.getValue();
But it returns null. Can anyone suggest me how can I retrive cookie on filter.
In order to retrieve your cookie, you should do the following:
for (Cookie c : requestContext.getCookies().values())
{
if (c.getName().equals("token")) {
cookie = c;
break;
}
}
Honestly, I don't know why you could not retrieve your cookie by its key, since the ContainerRequestContext documentation states that getCookies returns
a read-only map of cookie name (String) to Cookie.
when i try to setExpressCheckout, i get ack = success but not token return.
the version of paypal api is 87.0
Here the wsdl link : https://www.sandbox.paypal.com/wsdl/PayPalSvc.wsdl
here to command i use in axis2-1.6.1 to generate java code
-uri https://www.sandbox.paypal.com/wsdl/PayPalSvc.wsd -p com.paypal.soap
here the link to the java code that generated using axis2 https://docs.google.com/open?id=0B97cB4uxjmztbGgxRER6VjBWcWc
here the code for SetExpressCheckout
PaymentDetailsType paymentDetails = new PaymentDetailsType();
BasicAmountType orderTotal = new BasicAmountType();
orderTotal.setCurrencyID(CurrencyCodeType.USD);
orderTotal.setString("10.00");
paymentDetails.setOrderTotal(orderTotal);
paymentDetails.setPaymentAction(PaymentActionCodeType.Sale);
SetExpressCheckoutRequestDetailsType requestDetailsType = new SetExpressCheckoutRequestDetailsType();
requestDetailsType.setCancelURL(buyer.getCancelUrl());
requestDetailsType.setReturnURL(buyer.getReturnUrl());
requestDetailsType.setPaymentDetails(new PaymentDetailsType[]{paymentDetails});
SetExpressCheckoutRequestType requestType = new SetExpressCheckoutRequestType();
requestType.setVersion("87.0");
requestType.setSetExpressCheckoutRequestDetails(requestDetailsType);
SetExpressCheckoutReq req = new SetExpressCheckoutReq();
req.setSetExpressCheckoutRequest(requestType);
RequesterCredentials requesterCredentials = new RequesterCredentials();
CustomSecurityHeaderType customSecurityHeaderType = new CustomSecurityHeaderType();
UserIdPasswordType userIdPasswordType = new UserIdPasswordType();
userIdPasswordType.setUsername("<username>");
userIdPasswordType.setPassword("<pass>");
userIdPasswordType.setSignature("<signature>");
customSecurityHeaderType.setCredentials(userIdPasswordType);
requesterCredentials.setRequesterCredentials(customSecurityHeaderType);
String endPoint = null;
endPoint = "https://api-3t.sandbox.paypal.com/2.0/"; //sandbox API Signature
PayPalAPIInterfaceServiceStub stub = new PayPalAPIInterfaceServiceStub(endPoint);
stub._getServiceClient().getOptions().setProperty(HTTPConstants.CHUNKED, false);
SetExpressCheckoutResponse setExpressCheckout = stub.setExpressCheckout(req, requesterCredentials);
SetExpressCheckoutResponseType checkoutResponse = setExpressCheckout.getSetExpressCheckoutResponse();
Calendar timestamp = checkoutResponse.getTimestamp();
String strdate = null;
SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy hh:mm:ss");
if (timestamp != null) {
strdate = sdf.format(timestamp.getTime());
}
System.out.println("Date:" + strdate);
System.out.println("CorrelationID:" + checkoutResponse.getCorrelationID());
System.out.println("ack :" + checkoutResponse.getAck());
if (checkoutResponse.getErrors() != null && checkoutResponse.getErrors().length > 0) {
PayPalAPIInterfaceServiceStub.ErrorType[] errors = checkoutResponse.getErrors();
for (int i = 0; i < errors.length; i++) {
System.out.println(errors[i].getErrorCode());
System.out.println(errors[i].getLongMessage());
}
}
System.out.println("token:" + checkoutResponse.getToken());
here the result that i get
Date:17/04/2012 12:33:38
CorrelationID:a7c9fe7283bd
ack :Success
token:null
how i get ack success but token is null?
the contact person for paypal said that there is an EC token already be generated for CorrelationID:a7c9fe7283bd .
thanks in advance.
i have to use setExpressCheckoutResponse.getExtraElement().getText() to get the token. why setExpressCheckoutResponse.getToken() return null?
If you look into mentioned wsdl file, at the beginning you'll notice the following:
<wsdl:definitions
ns:version="89.0"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns="http://schemas.xmlsoap.org/wsdl/"
... >
Meaning that the version of API which should be used is 89.0 - don't remember where it's specified in PayPal API documentation, but this was mentioned there for sure.
Let me know if you still encounter this issue, since I've managed to set up PayPal Express Checkout using SOAP in Java recently and can help with that.
I just came across this issue and found the answer (this is for C#, I am not sure if it applies to Java):
https://www.x.com/developers/paypal/forums/soap/paypal-api-aa-and-net-wcf-undeserialized-fields
Look in the generated code for the web service (Reference.cs) and find the AbstractResponseType. The last property is Any(). Change the attribute to match this (to ignore the property):
[System.Xml.Serialization.XmlIgnoreAttribute()]
public System.Xml.XmlElement Any {
get {
return this.anyField;
}
set {
this.anyField = value;
}
}
Following this, recompile and test again and you should now receive the Token property set correctly.
If you regenerate the web service code, this change will of course get replaced and you will have to re-do it unless PayPal fixes this. BTW, my WSDL Version number is 98.0 at this time.
Gary Davis
I'm trying to enable SSO under Tomcat such that users who go to http://mydomain.com and http://www.mydomain.com will have their session cookie available for requests made to http://subdomain.mydomain.com. All three of these domains go to the same webapp, so ideally I'd like to not mess with SSO at all and just set the domain on the standard JSESSIONID cookie.
However, that doesn't seem possible, so I'm trying to enable Tomcat's SSO Valve. The problem is that the Valve requires a definition of a Realm, and a Realm is supposed to specify a database of users and roles. However, I am not using container-based authentication nor role-based authorization, so I do not need or want to configure a Realm. All I want is for the session cookie(s) to be able to be shared across each of these different subdomains.
Is there any straightforward way to do this?
Edit
My current workaround for this is to have the server redirect every incoming request to the "canonical" server name. This works well enough, but obviously it is not actually solving the problem.
We were having the same problem and created a Tomcat Valve that would overwrite or set the Domain part of the session Cookie. Quite a simple thing and it already works for many years. The code goes like this:
public class CrossSubdomainSessionValve extends ValveBase {
public CrossSubdomainSessionValve() {
super();
info = "common-tomcat-CrossSubdomainSessionValve";
}
#Override
public void invoke(Request request, Response response) throws IOException, ServletException {
// cookie will only need to be changed, if this session is created by this request.
if (request.getSession(true).isNew()) {
Cookie sessionCookie = findSessionCookie(response.getCookies());
if (sessionCookie != null) {
String cookieDomainToSet = getCookieDomainToSet(request.getServerName());
if (cookieDomainToSet != null) {
// changing the cookie only does not help, because tomcat immediately sets
// a string representation of this cookie as MimeHeader, thus we also
// have to change this representation
replaceCookie(response.getCoyoteResponse().getMimeHeaders(), sessionCookie, cookieDomainToSet);
}
}
}
// process the next valve
getNext().invoke(request, response);
}
protected Cookie findSessionCookie(Cookie[] cookies) {
if (cookies != null)
for (Cookie cookie : cookies)
if (Globals.SESSION_COOKIE_NAME.equals(cookie.getName())) {
return cookie;
return null;
}
protected void replaceCookie(MimeHeaders headers, Cookie originalCookie, String domainToSet) {
// if the response has already been committed, our replacementstrategy will have no effect
// find the Set-Cookie header for the existing cookie and replace its value with new cookie
for (int i = 0, size = headers.size(); i < size; i++) {
if (headers.getName(i).equals("Set-Cookie")) {
MessageBytes value = headers.getValue(i);
if (value.indexOf(originalCookie.getName()) >= 0) {
if (originalCookie.getDomain() == null) {
StringBuilder builder = new StringBuilder(value.getString()).append("; Domain=").append(domainToSet);
value.setString(builder.toString());
} else {
String newDomain = value.getString().replaceAll("Domain=[A-Za-z0-9.-]*", "Domain=" + domainToSet);
value.setString(newDomain);
}
}
}
}
}
protected String getCookieDomainToSet(String cookieDomain) {
String[] parts = cookieDomain.split("\\.");
if (parts.length >= 3) {
return "." + parts[parts.length - 2] + "." + parts[parts.length - 1];
}
return null;
}
public String toString() {
return ("CrossSubdomainSessionValve[container=" + container.getName() + ']');
}
}
The algorithm works like this:
- Only if the session is new - find the session cookie
- Get the requested host name
- Split the host name with '.'
- If it has at least 3 parts (like www.google.de), remove first part (to .google.de)
- Reset the cookie
In your Context configuration you can apply the valve like this
<Valve className="my.package.CrossSubdomainSessionValve" httpOnlyEnabled="true" />
Caveat: In the code the Valve creates a session if no session was created before and does not care if you need a session at all...
Hope that helps... Good luck!