I have problem while using crosswalk in shared mode with setting User-agent and handling cookies
1.While using crosswalk in normal mode there is an api org.xwalk.core.internal.XWalkViewBridge with which I set the user agent for the webview
java.lang.reflect.Method ___getBridge=XWalkView.class.getDeclaredMethod("getBridge"); ___getBridge.setAccessible(true);
XWalkViewBridge xWalkViewBridge = null;
xWalkViewBridge = (XWalkViewBridge)___getBridge.invoke(webView);
XWalkSettings xWalkSettings = xWalkViewBridge.getSettings();
xWalkSettings.setUserAgentString(userAgent);
2.And there is another api known as org.xwalk.core.internal.XWalkCookieManager which is used to handle Cookies on webview.
Both of these apis are not accessible in shared mode, Kindly suggest how to set the user agent and handle cookies while using crosswalk in shared mode.
You can use the following method of XWalkView public API to set User-Agent:
setUserAgentString(java.lang.String userAgent)
See Javadoc for more details.
But regarding XWalkCookieManager I can't suggest anything. Let us know if you find something useful.
I used the following method to setUserAgent as told by #comrade
mXWalkView.setUserAgentString("MyCustomUserAgent")
For settings cookies I adopted the following approach. First I get all the cookies that are store in cookieStore of android covert them to String and make a list of strings.
public List<String> getAllCookies(){
List<Cookie> cookies=instance.cookieStore.getCookies();
List<String> cookiesList = new ArrayList<String>();
for(Cookie cookie: cookies)
{
String cookieString = cookie.getName() + "=" + cookie.getValue() + "; Path=" + cookie.getPath();// + "; Domain=" + cookie.getDomain()
String expires = null;
if (cookie.getExpiryDate() != null) {
expires = android.text.format.DateFormat.format("EEE, dd-MMM-yyyy hh:mm:ss z", cookie.getExpiryDate()).toString();
cookieString = cookieString + "; Expires=" + expires;
}
cookiesList.add(cookieString);
}
return cookiesList;
}
Once this is done in my CustomXWalkActivity onPageLoadFinished I get list of those cookie convert them to JSONObject and then call a javascript function syncCookies
private boolean isLoadingFirstTime=true;
private void updateCookies() {
List<String> cookies = getAllCookies();
JSONObject cookiesObj = new JSONObject();
for(String cookie : cookies){
Log.d(TAG, "cookie:" + cookie);
int iend = cookie.indexOf("=");
try {
cookiesObj.put(cookie.substring(0, iend), cookie);
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Log.d(TAG, "All the cookies:" + cookiesObj);
StringBuilder buf=new StringBuilder("javascript:syncCookies('"+cookiesObj+"')");
mXWalkView.load(buf.toString(), null);
}
#Override
public void onLoadFinished(XWalkView view, String url) {
Log.d(TAG, "load finished:"+url);
if(isLoadingFirstTime){
updateCookies();
isLoadingFirstTime=false;
}
mXWalkView.clearCache(true);
super.onLoadFinished(view, url);
}
And then on Javascript side I have the following code to set cookies on the document
function syncCookies(cookies){
console.log("sync cookies called",cookies);
var allCookies=JSON.parse(cookies);
for (var key in allCookies) {
console.log("cookie to be set", allCookies[key]);
document.cookie=testCookies[key];
}
}
Related
I have been trying to use this cordova plugin, which uses NanoHttpd to handle requests.
By default, Nanohttpd handles some of the HTTP methods, like GET, POST, CONNECT, PROPFIND, PATCH, etc.
I have been trying to figure out how to implement a custom handler so that nanohttpd can handled more HTTP methods like: NOTIFY and SUBSCRIBE
#Override
public Response serve(IHTTPSession session) {
Log.d(this.getClass().getName(), "New request is incoming!");
String requestUUID = UUID.randomUUID().toString();
PluginResult pluginResult = null;
try {
pluginResult = new PluginResult(
PluginResult.Status.OK, this.createJSONRequest(requestUUID, session));
} catch (JSONException e) {
e.printStackTrace();
}
pluginResult.setKeepCallback(true);
this.webserver.onRequestCallbackContext.sendPluginResult(pluginResult);
while (!this.webserver.responses.containsKey(requestUUID)) {
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
JSONObject responseObject = (JSONObject) this.webserver.responses.get(requestUUID);
Log.d(this.getClass().getName(), "responseObject: " + responseObject.toString());
Response response = null;
try {
response = newFixedLengthResponse(
Response.Status.lookup(responseObject.getInt("status")),
getContentType(responseObject),
responseObject.getString("body")
);
Iterator<?> keys = responseObject.getJSONObject("headers").keys();
while (keys.hasNext()) {
String key = (String) keys.next();
response.addHeader(
key,
responseObject.getJSONObject("headers").getString(key)
);
}
} catch (JSONException e) {
e.printStackTrace();
}
return response;
}
I added a simple notify Response to handle any incoming request, referring from here - https://stackoverflow.com/a/27645191/2096740
public Response notify(IHTTPSession session) {
StringBuilder text = new StringBuilder("<html><body>");
text.append("<h1>Url: ");
text.append(session.getUri());
text.append("</h1><br>");
Map<String, String> queryParams = session.getParms();
if (queryParams.size() > 0) {
for (Map.Entry<String, String> entry : queryParams.entrySet()) {
String key = entry.getKey();
String value = entry.getValue();
text.append("<p>Param '");
text.append(key);
text.append("' = ");
text.append(value);
text.append("</p>");
}
} else {
text.append("<p>no params in url</p><br>");
}
return newFixedLengthResponse(text.toString());
}
But this returnsBAD REQUEST: Syntax error. HTTP verb NOTIFY unhandled.
Documentation is not clear and there is not much info circulating on extending Nanohttpd behavior on SO or via web results.
What is the correct way to do this? How can I extend it ?
The check for Method is actually locked in an enum. It is hardcoded and there is no other method to expand.
The getMethod instance itself is a enum type of Method.
Since, I couldn't find any other solution, I therefore conclude it is not possible to do this stuff in Nanohttpd. All its versions in Maven dont support this.
The reason they have
Some built-in support for HEAD, POST and DELETE requests. You can
easily implement/customize any HTTP method, though.
mentioned in their feature list is because the original version had method as a String. It has changed since.
Feature list not been updated to reflect this change.
I am using the below code to log into Facebook. Once i get the code, using that i get access token and then query graph api and get some basic details.
#RequestMapping(value = "/fblogin")
public String inititateFBlogin(ModelMap model) {
System.out.println("in FB login ");
String fbAuthURL = fbConnectionService.getFBAuthUrl();
return "redirect:"+fbAuthURL;
}
public String getFBAuthUrl() {
String fbLoginUrl = "";
try {
fbLoginUrl = "http://www.facebook.com/dialog/oauth?" + "client_id="
+ FBConnection.FB_APP_ID + "&redirect_uri="
+ URLEncoder.encode(FBConnection.REDIRECT_URI, "UTF-8")
+ "&scope=email";
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return fbLoginUrl;
}
But to logout , i am hitting the URL in below format.
//https://www.facebook.com/logout.php?next=[YourAppURL]&access_token=[ValidAccessToken]
#RequestMapping(value = "/fblogout", method=GET)
public String fbLogOut(ModelMap model) {
String fbLogoutURL = "https://www.facebook.com/logout.php?confirm=1&next=";
String appURL = "http://localhost:15005/abc";
String accessToken = accessTokenFB ;
String logOutURL = fbLogoutURL+appURL+"&access_token="+accessToken;
return "redirect:"+logOutURL;
}
But looks like the above FB url always redirects to the FB homepage.
Is there any way that i can log out by simply calling any FB service through java, I would rather avoid going down to the javascript SDK.
Many thanks.
You can logout an access token by sending a DELETE (instead of GET/POST) request to /me/permissions
https://developers.facebook.com/docs/facebook-login/permissions/requesting-and-revoking
https://developers.facebook.com/docs/graph-api/reference/user/permissions/
curl -X DELETE https://graph.facebook.com/me/permissions?access_token=ABC
We're using stormpath with Java & also trying to combine form Login with REST API authentication on the same application.
I've setup stormpath servlet plugin as described here https://docs.stormpath.com/java/servlet-plugin/quickstart.html... This works very fine.
Now, on the same application, we have APIs where I've implemented oAuth authentication with stormpath see here http://docs.stormpath.com/guides/api-key-management/
The first request for an access-token works fine by sending Basic Base64(keyId:keySecret) in the request header and grant_type = client_credentials in the body. Access tokens are being returned nicely. However trying to authenticate subsequent requests with the header Bearer <the-obtained-access-token> does not even hit the application before
returning the following json error message...
{
"error": "invalid_client",
"error_description": "access_token is invalid."
}
This is confusing because I've set breakpoints all over the application and I'm pretty sure that the API request doesn't hit the anywhere within the application before stormpath kicks in and returns this error. And even if stormpath somehow intercepts the request before getting to the REST interface, this message doesn't make any sense to me because i'm certainly making the subsequent API calls with a valid access-token obtained from the first call to get access-token.
I have run out of ideas why this could be happening but i'm suspecting that it may have something to do with stormpath config especially with a combination
of form Login/Authentication for web views and oAuth Athentication for REST endpoints. With that said, here's what my stormpath.properties looks like. Hope this could help point at anything I may be doing wrong.
stormpath.application.href=https://api.stormpath.com/v1/applications/[app-id]
stormpath.web.filters.authr=com.app.security.AuthorizationFilter
stormpath.web.request.event.listener = com.app.security.AuthenticationListener
stormpath.web.uris./resources/**=anon
stormpath.web.uris./assets/**=anon
stormpath.web.uris./v1.0/**=anon
stormpath.web.uris./** = authc,authr
stormpath.web.uris./**/**=authc,authr
Help with this would be highly appreciated.
The problem might be related to an incorrect request.
Is it possible for you to try this code in your app?:
private boolean verify(String accessToken) throws OauthAuthenticationException {
HttpRequest request = createRequestForOauth2AuthenticatedOperation(accessToken);
AccessTokenResult result = Applications.oauthRequestAuthenticator(application)
.authenticate(request);
System.out.println(result.getAccount().getEmail() + " was successfully verified, you can allow your protect operation to continue");
return true;
}
private HttpRequest createRequestForOauth2AuthenticatedOperation(String token) {
try {
Map<String, String[]> headers = new LinkedHashMap<String, String[]>();
headers.put("Accept", new String[]{"application/json"});
headers.put("Authorization", new String[]{"Bearer " + token});
HttpRequest request = HttpRequests.method(HttpMethod.GET)
.headers(headers)
.build();
return request;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
I've prepared an example that demonstrates oauth token creation as well as authorized access to protected pages using access tokens.
It builds off of the servlet example in the Stormpath SDK. The repo can be found here: https://github.com/stormpath/stormpath-java-oauth-servlet-sample
It demonstrates running a servlet application and having an out-of-band program get and use oauth tokens to access protected resources.
The core of the oauth part is in TokenAuthTest.java:
public class TokenAuthTest {
public static void main(String[] args) throws Exception {
String command = System.getProperty("command");
if (command == null || !("getToken".equals(command) || "getPage".equals(command))) {
System.err.println("Must supply a command:");
System.err.println("\t-Dcommand=getToken OR");
System.err.println("\t-Dcommand=getPage OR");
System.exit(1);
}
if ("getToken".equals(command)) {
getToken();
} else {
getPage();
}
}
private static final String APP_URL = "http://localhost:8080";
private static final String OAUTH_URI = "/oauth/token";
private static final String PROTECTED_URI = "/dashboard";
private static void getToken() throws Exception {
String username = System.getProperty("username");
String password = System.getProperty("password");
if (username == null || password == null) {
System.err.println("Must supply -Dusername=<username> -Dpassword=<password> on the command line");
System.exit(1);
}
PostMethod method = new PostMethod(APP_URL + OAUTH_URI);
method.setRequestHeader("Origin", APP_URL);
method.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
method.addParameter("grant_type", "password");
method.addParameter("username", username);
method.addParameter("password", password);
HttpClient client = new HttpClient();
client.executeMethod(method);
BufferedReader br = new BufferedReader(new InputStreamReader(method.getResponseBodyAsStream()));
String readLine;
while(((readLine = br.readLine()) != null)) {
System.out.println(readLine);
}
}
private static void getPage() throws Exception {
String token = System.getProperty("token");
if (token == null) {
System.err.println("Must supply -Dtoken=<access token> on the command line");
System.exit(1);
}
GetMethod method = new GetMethod(APP_URL + PROTECTED_URI);
HttpClient client = new HttpClient();
System.out.println("Attempting to retrieve " + PROTECTED_URI + " without token...");
int returnCode = client.executeMethod(method);
System.out.println("return code: " + returnCode);
System.out.println();
System.out.println("Attempting to retrieve " + PROTECTED_URI + " with token...");
method.addRequestHeader("Authorization", "Bearer " + token);
returnCode = client.executeMethod(method);
System.out.println("return code: " + returnCode);
}
}
I want to know how can I get a HTTP request information from Java, I am using Restlet framework but I don't want to limit it with that. As I have been struggling to figure it out with restlet and yet I can't. I am attaching a screenshot of my GAE console log,
I need to get that locahost (domain), it could be abc.com or xyz.com in actual production environment.
Here is the restlet code I have for this app:
Redirector proxy = new Redirector(getContext(), target,
Redirector.MODE_SERVER_OUTBOUND){
String target = "https://dl.x.com/u/123/";
#Override
public void handle(Request request, Response response) {
String path = request.getResourceRef().getHostIdentifier() +
request.getResourceRef().getPath();
try {
URL url = new URL(path);
String host = url.getHost();
String pathParts = url.getPath();
if(pathParts.isEmpty() || pathParts.equals(ROOT_URI)){
pathParts = "/index.html"; // Hard-wired for now
}
String targetPattern = target + host + pathParts;
System.out.println("Target URL = " + targetPattern);
this.setTargetTemplate(targetPattern);
} catch (MalformedURLException e){
e.printStackTrace();
}
super.handle(request, response);
}
};
getConnectorService().getClientProtocols().add(Protocol.HTTP);
return proxy;
}
The problem here is the String host gets the value of app-x.appspot.com, I need to get the one shown in the picture.
You can get this information from the request-object:
request.getRequestURI()
my application suppose to connect a web service and active some of his functions.
first, the application activate a "Login" function that gets as arguments username and password, the function search the user name and the password in a database and returning me if im logged in or not. and creating a session vars for me like:
Session["Username"] = User.Username;
Session["FullName"] = User.FullName;
and more...
and than i want to active another webservice function - UpdateProfile
that change my profile values on the database.
so, my application has a class with some private classes (asynctasks)
and every asynctask is responsible for one function in the webservice.
for example - the login asynctask:
private class LoginAsyncTask extends AsyncTask<String, String, User>
{
private String METHODNAME = "Login";
private String SOAPACTION = "http://tempuri.org/Login";
and more...
in this login asynctask i parse the comming back cookies like this:
cookies is a HashMap<String, String>();
try
{
//respHeaders = trans.call(SOAPACTION, envelope, null);
reshttpHeaders = trans.call(SOAPACTION, envelope, null);
}
catch (Exception e)
{
//connection error.
e.printStackTrace();
return null;
}
cookies.clear();
if (reshttpHeaders!=null) {
for (int i = 0; i < reshttpHeaders.size(); i++) {
HeaderProperty hp = (HeaderProperty)reshttpHeaders.get(i);
String key = hp.getKey();
String value = hp.getValue();
if (key!=null && value!=null) {
if (key.equalsIgnoreCase("set-cookie")){
String cookieString = value.substring(0,value.indexOf(";") );
cookies.put(cookieString.substring(0, cookieString.indexOf("=")),cookieString.substring(cookieString.indexOf("=")+1) );
break;
}
}
}
}
and than, in another asynctask called UpdateProfileAsynctask
im sending this cookie like this:
List<HeaderProperty> httpHeaders = new ArrayList<HeaderProperty>();
for (String cookie:cookies.keySet()) {
httpHeaders.add(new HeaderProperty("Cookie", cookie + "=" + cookies.get(cookie)));
}
try
{
//trans.call(SOAPACTION, envelope, reqHeaders);
trans.call(SOAPACTION, envelope, httpHeaders);
}
when i try to catch this packets with wireshark i see that the cookie that i get is:
Set-Cookie: ASP.NET_SessionId=kmwn4l2qzc0k1anfk1du4ty1; path=/; HttpOnly\r\n
and my cookie that i send is:
Cookie: ASP.NET_SessionId=kmwn4l2qzc0k1anfk1du4ty1\r\n
The problem is that the webservice dont recognize me (the second request is in the 20 minutes period).
this part of the code in the webservice running:
if (Session["Username"] == null)
return "Cant Update profile now, Your connection seems to be timeout";
and i get this message all time. but its stange that sometimes its working :/
thanks.
I fix my problems after reading your questions, thank you.
My code is like the folloiwng:
HeaderProperty headerPropertySessionId = new HeaderProperty("Cookie", "key1=value1");
List headerPropertyList = new ArrayList();
headerPropertyList.add(headerPropertySessionId);