Azure SDK for Java - sample program throwing InvalidKeyException - java

Using Azure Storage SDK for Java, I am trying to perform basic create, read, update, delete operations on Azure Table Storage as given in the link below:
https://azure.microsoft.com/en-us/documentation/articles/storage-java-how-to-use-table-storage/
Sample program for creating a table:
package com.azure.test;
import java.io.UnsupportedEncodingException;
import com.microsoft.azure.storage.*;
import com.microsoft.azure.storage.table.CloudTable;
import com.microsoft.azure.storage.table.CloudTableClient;
import com.microsoft.windowsazure.core.utils.Base64;
public class App
{
public static void main( String[] args ) throws StorageException, UnsupportedEncodingException
{
String storageConnectionString =
"DefaultEndpointsProtocol=http;" +
"AccountName=accountname;" +
"AccountKey=storagekey;"+
"EndpointSuffix=table.core.windows.net";
try
{
// Retrieve storage account from connection-string.
CloudStorageAccount storageAccount =
CloudStorageAccount.parse(storageConnectionString);
CloudTableClient tableClient = storageAccount.createCloudTableClient();
//Create the table if it doesn't exist.
String tableName = "MyTable";
CloudTable cloudTable = tableClient.getTableReference(tableName);
cloudTable.createIfNotExists();
}
catch (Exception e)
{
// Output the stack trace.
e.printStackTrace();
System.out.println(e.getMessage());
}
}
}
The code seems to be fairly simple to understand. It would connect to the Azure table storage and if a table with a given name does not exist it will create it. But I am getting a InvalidKeyException(full exception pasted below).
java.security.InvalidKeyException: Storage Key is not a valid base64 encoded string.
at com.microsoft.azure.storage.StorageCredentials.tryParseCredentials(StorageCredentials.java:68)
at com.microsoft.azure.storage.CloudStorageAccount.tryConfigureServiceAccount(CloudStorageAccount.java:408)
at com.microsoft.azure.storage.CloudStorageAccount.parse(CloudStorageAccount.java:259)
at com.azure.test.App.main(App.java:71)
I am surprised that not many people using Azure Storage are facing this issue. I tried to encode the storage key using and used the encoded key in the connection string but still no use.
String encodedKey=Base64.encode(storageKey.getBytes())
String storageConnectionString =
"DefaultEndpointsProtocol=http;" +
"AccountName=accountname" +
"AccountKey="+encodedKey+
"EndpointSuffix=table.core.windows.net;";
Can anyone please help me with this? I searched in google a lot and I am able to find one user raised a similar issue on discus but there is no answer provided for that or rather that answer was not helpful.

Update:/Resolution of the issue
First of all I ensured that all the properties in connection string are separated by ';' as suggested by Gaurav(below)
It turns out that I have to manually set the proxy settings in my program since my company work machine is using a proxy to connect to the internet.
System.getProperties().put("http.proxyHost", "myproxyHost");
System.getProperties().put("http.proxyPort", "myProxyPort");
System.getProperties().put("http.proxyUser", "myProxyUser");
System.getProperties().put("http.proxyPassword","myProxyPassword");
Updating the proxy settings solved the issue for me.

Please change the following line of code:
String storageConnectionString =
"DefaultEndpointsProtocol=http;" +
"AccountName=accountname" +
"AccountKey="+encodedKey+
"EndpointSuffix=table.core.windows.net;";
To
String storageConnectionString =
"DefaultEndpointsProtocol=http;" +
"AccountName=accountname" +
";AccountKey="+encodedKey+
";EndpointSuffix=core.windows.net;";
Essentially in your code, there was no separator (;) between AccountName, AccountKey and EndpointSuffix. Also, if you're connecting to standard endpoint (core.windows.net), you don't need to specify EndpointSuffix in your connection string.
Lastly, please ensure that the account key is correct.

Related

Has anyone done a FitNesse TEST that queries to REAL Database? I can't make Fitnesse connect successfully

I'm asking because ALL examples I find in Google, are the same from the Fitnesse tutorial: a very simple query to a list or array in memory, NOT A REAL Database.
Yes, Fixtures never have to deal with that, but how am I supposed to test my fixtures if I can't even make the connection to the DB in a simulation of an "API"?
What I'm trying to simulate is the call from a FitNesse Fixture to query in Java into a PostgreSQL database/table. In this simple example I'm trying to obtain, at least one column from one row, in one table. When I execute the code, it runs perfectly by it's own. The problem is when trying to execute from Fitnesse through the fixture. It always fails with a ClassNotFoundException, when calling the JDBC driver. This doesn't happen by running the code by it's own.
Here is the code that does the query:
package queriespackage;
import java.sql.*;
public class testQuery01 {
public static Connection openDBConnection(){
Connection connectionString = null;
try {
String dbhost = "SOMEURL";//Redacted
String port = "SOMEPORT";//Redacted
String dbname = "THEDBNAME";//Redacted
String username = "SOMEUSER";//Redacted
String password = "SOMEPASSWORD";//Redacted
String driverJDBC = "org.postgresql.Driver";
Class.forName(driverJDBC);
connectionString = DriverManager.getConnection("jdbc:postgresql://" + dbhost + ":" + port + "/" + dbname,username,password);
connectionString.setAutoCommit(false);
} catch (SQLException e) {
e.printStackTrace(System.err);
System.exit(0);
} catch (Exception e) {
System.err.println( e.getClass().getName()+": "+ e.getMessage() );
System.exit(0);
};
return connectionString;
};
public static ResultSet executeQuery(Connection connectionString, int intAccountId) throws SQLException{
Statement querySession = connectionString.createStatement();
//The query string
String queryString = "SELECT DISTINCT "
+ "account_search.account_id,"
+ "account_search.account_name"
+ " FROM account_search "
+ " WHERE"
+ " account_search.account_id = "+ intAccountId
+ "LIMIT 1";
ResultSet queryResult = querySession.executeQuery(queryString);
return queryResult;
};
public static String processQueryResult(ResultSet queryResult) throws SQLException{
String strQueryValueReturned = null;
while (queryResult.next()) {
strQueryValueReturned = queryResult.getString("account_name");
};
return strQueryValueReturned;
};
public static boolean closeDBConnection(Connection connectionString){
try {
if(connectionString!=null){
connectionString.close();
}
} catch (SQLException e) {
System.err.println( e.getClass().getName()+": "+ e.getMessage() );
System.exit(0);
};
return true;
};
public static String testQuery(int intAccountId) throws SQLException, ClassNotFoundException{
boolean bolConnectionStatus = false;
String strValueReturned = null;
Connection connectionString = openDBConnection();
if(connectionString != null){
ResultSet qryQueryResult = executeQuery(connectionString, intAccountId);
strValueReturned = processQueryResult(qryQueryResult);
bolConnectionStatus = closeDBConnection(connectionString);
if(!bolConnectionStatus){
System.exit(0);
}
}else{
System.exit(0);
};
return strValueReturned;
};
};
If I add a Main method to that code, passing it the argument value for "intAccountId", it successfully returns the name of the account "account_name", just as expected.
Now here's the Fixture that should be called by the FitNesse test:
package fixturespackage;
import java.sql.SQLException;
import queriespackage.testQuery01;
public class testFixture01{
private int Int_AccountId;
//Fixture Constructor (setter)
public testFixture01(int Int_AccountId){
this.Int_AccountId = Int_AccountId;
};
public String query() throws SQLException, ClassNotFoundException{
return testQuery01.testQuery(Int_AccountId);
};
};
Just as the FitNesse guide says, there must be a "query" method, that does the actual call to the interface in the DB. I had to add a constructor instead of the "setter", because FitNesse actually demands it: "Could not invoke constructor for fixturepackage.testFixture01"
Here's the FitNesse page:
!***> System Variables
!define TEST_SYSTEM {slim}
!path C:\FitnessTest\bin
*!
|Query: fixturespackage.testFixture01|21 |
|Str_AccountName |
|SomeName |
Here's a Screenshot of my BuildPath, so you can see I have the JDBC Library for Java 8, JDK 1.8, JRE 1.8... and the "org.postgresql.Driver.class" is included in the project.
This is the error I receive, when running from FitNesse:
This is the error I get, when debugging the line where FitNesse failed by using Inspect tool:
... and YES, I also tried by hard coding the name of the JDBC:
I have searched a lot for a REAL LIFE example, both here, the FitNesse Guide and Google.
The FitNesse Guide might be extensive, but let's be sincere, it's full of "dirty word here", unrealistic and incomplete examples and missing a lot of information.
So, asking again, has anyone done a REAL LIFE test making queries, using FitNesse, that could help me find out what am I doing wrong?
I have to admit I've only done limited database tests with FitNesse, but I have used them (to query DB2).
I did not use query tables (or wrote my own fixtures to query), but instead used jdbcslim in combination with script tables and scenario's.
That fact that the driver class cannot be found suggests that although the jar is present on the classpath in your IDE it is not available when FitNesse is running your fixture code.
I notice you specify the classpath as a single directory in the wiki. In Java that means that all class files should be in that directory (as .class files, in the right subdirectory for their defined package). It will not pick up any jars (or zips) in that directory. Did you unpack your database driver's jar to that directory? If not, you need to add a !path line pointing to the jar (so the entire path including the filename) with the database driver.
Now listing every jar you need can quickly become cumbersome, so you can also use wildcards. I tend to copy all the jars I need to a single directory, that also contains my fixture .class files, and add a single !path line loading all jars in that directory.
So if you also copied your database driver to the directory in you question you could ensure it, and your own fixture, to be available via
!path C:\FitnessTest\bin
!path C:\FitnessTest\bin\*.jar

Java can not read .p12 file stored in Oracle Blob column during Keystore initialization

I am trying to perform non-common functionality using Java inside Oracle Database schema, but after several weeks I got stoned with weird java behavior.
My desired functionality
I want to apply a digital signature over XML document (using pre-existing p12 certificate file) using Oracle PL/SQL procedures and Java classes stored in the same database schema (I am trying to avoid using external API/web services for the digital signature functionality).
Context Info
This is a brief overview of the solution design:
1. I want to use java classes stored in the same Oracle Database instance
2. I want to call java classes from PL/SQL
3. The main signature functionality will happen inside Java class which will connect to Oracle Database a get two Blob files: the digital certificate stored as p12 file inside one Blob column and the XML file to be signed stored in another Blob column.
The problem
After several testing I detected a weird java behavior. Java can read the Blob columns contents without problem (it can explore the size of the blob, print the contents, etc.)
But when I try to use a Blob column (the one which contains the p12 file) as an InputStream for the Keystore class, java can not load the certificate into the Keystore.
Here is a piece of code just to see if you have any ideas about how to force the Keystore class to read the contents of Blob as input...
public static String Blob_X509Cert_Test() {
String v_hilera = null;
try {
Connection con = DriverManager.getConnection
("jdbc:oracle:thin:#myserver:15210:mysid",
"myuseraccount","mypassword");
Statement stmt=con.createStatement();
ResultSet rs = stmt.executeQuery("select blob_cert from tmp_blob");
if (rs.next()) {
Blob v_blob = rs.getBlob("blob_cert");
InputStream v_is = v_blob.getBinaryStream();
int v_b = v_is.read();
KeyStore p12;
try {
p12 = KeyStore.getInstance("pkcs12");
try {
p12.load(v_is, "p12password".toCharArray());
Enumeration<String> e = p12.aliases();
while (e.hasMoreElements()) {
String alias = (String) e.nextElement();
X509Certificate c = (X509Certificate)
p12.getCertificate(alias);
Principal subject = c.getSubjectDN();
String subjectArray[] =
subject.toString().split(",");
for (String s : subjectArray) {
String[] str = s.trim().split("=");
String key = str[0];
String value = str[1];
}
}
} catch (NoSuchAlgorithmException | CertificateException e1) {
e1.printStackTrace();
}
} catch (KeyStoreException e1) {
e1.printStackTrace();
}
return v_hilera;
}
This piece of code could be incomplete (I put it here just for help a conceptual understanding, but I am ready to share more code if necessary).
In my research, I isolete the problem to the Keystore.load() method which can not read the Blob contents (perhaps, the problem could be on another site).
If I use local file system as input stream for the Keystore.load() everything works as expected...
If you try this piece of code:
FileInputStream v_fis = new FileInputStream("C:/temp/TD_Cramos_Test.p12");
System.out.println("v_fis.available(): " + v_fis.available());
Result: 6736 (size of the file contents)
If you try same functionality but with Blob "file" the result will be cero bytes:
InputStream v_is = v_blob.getBinaryStream();
System.out.println("v_is.available(): " + v_is.available());
Result: 0 (for some reason, the blob contents is no read)
Any help or guidance will be really appreciated,
Carlos.

Java - Create domain in Amazon SimpleDB

I'm working with Amazon SimpleDB and attempting the creation of a DB using the following tutorial . Basically it throws an error i.e. Error occured: java.lang.String cannot be cast to org.apache.http.HttpHost. The full stacktrace is as below:
Error occured: java.lang.String cannot be cast to org.apache.http.HttpHost
java.lang.ClassCastException: java.lang.String cannot be cast to org.apache.http.HttpHost
at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:416)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:906)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:805)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:784)
at com.xerox.amazonws.common.AWSQueryConnection.makeRequest(AWSQueryConnection.java:474)
at com.xerox.amazonws.sdb.SimpleDB.makeRequestInt(SimpleDB.java:231)
at com.xerox.amazonws.sdb.SimpleDB.createDomain(SimpleDB.java:155)
at com.amazonsimpledb.SDBexample1.main(SDBexample1.java:19)
My code is as below (note i have substituted the AWS access id and secret key with the actual values):
public static void main(String[] args) {
String awsAccessId = "My aws access id";
String awsSecretKey = "my aws secret key";
SimpleDB sdb = new SimpleDB(awsAccessId, awsSecretKey, true);
try {
Domain domain = sdb.createDomain("cars");
System.out.println(domain);
} catch (com.xerox.amazonws.sdb.SDBException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Any ideas as to why the above mentioned error is occurs.
I appreciate any assistance.
It seems you are using the Typica client library, which is pretty much unmaintained since mid 2011, see e.g. the rare commmits and the steady growing unresolved issues, where the latest one appears to be exactly yours in fact, see ClassCastException using Apache HttpClient 4.2:
According to the reporter, things appear to be functional once we downgrade back to Apache HttpClient 4.1, so that might be a temporary workaround eventually.
Either way I highly recommend to switch to the official AWS SDK for Java (or one of the other language SDKs), which isn't only supported and maintained on a regular fashion, but also closely tracks all AWS API changes (admittedly this isn't that critical for Amazon SimpleDB, which is basically frozen technology wise, but you'll have a much easier time using the plethora of AWS Products & Services later on).
In addition you could benefit from the AWS Toolkit for Eclipse in case you are using that IDE.
The SDK includes a couple of samples (also available via the Eclipse Toolkit wizard), amongst those one for SimpleDB - here's a condensed code excerpt regarding your example:
BasicAWSCredentials basicAWSCredentials = new BasicAWSCredentials(
awsAccessId, awsSecretKey);
AmazonSimpleDB sdb = new AmazonSimpleDBClient(basicAWSCredentials);
Region usWest2 = Region.getRegion(Regions.US_WEST_2);
sdb.setRegion(usWest2);
try {
// Create a domain
String myDomain = "MyStore";
System.out.println("Creating domain called " + myDomain + ".\n");
sdb.createDomain(new CreateDomainRequest(myDomain));
// ...
// Delete a domain
System.out.println("Deleting " + myDomain + " domain.\n");
sdb.deleteDomain(new DeleteDomainRequest(myDomain));
} catch (AmazonServiceException ase) {
// ...
} catch (AmazonClientException ace) {
// ...
}
Please try to create instance of SimpleDB with server and port and let me know if it works.
public SimpleDB objSimpleDB = null;
private String awsAccessKeyId = "access key";
private String awsSecretAccessKey = "secret key";
private boolean isSecure= true;
private String server = "sdb.amazonaws.com";
private int port=443;
try{
SimpleDB objSimpleDB = new SimpleDB(awsAccessKeyId, awsSecretAccessKey, isSecure, server, port);
Domain domain = objSimpleDB .createDomain("cars");
} catch (com.xerox.amazonws.sdb.SDBException e) {
//handle error
}

Connecting to PC to view shared folders from Android device

I am working on a samba client for Android. Given an IP address it should connect to it and browse the shared folders.
For this I use JCIFS. I dropped the jar in my Android project and added following code to connect to PC and get the list of files:
private void connectToPC() throws IOException {
String ip = "x.x.x.x";
String user = Constants.username + ":" + Constants.password;
String url = "smb://" + ip;
NtlmPasswordAuthentication auth = new NtlmPasswordAuthentication(user);
SmbFile root= new SmbFile(url, auth);
String[] files = root.list();
for (String fileName : files) {
Log.d("GREC", "File: " + fileName);
}
}
And I get in return: jcifs.smb.SmbAuthException: Logon failure: unknown user name or bad password.
But the credentials are correct. I also tried with another samba client from the android market that uses JCIFS and it successfully connected to that ip, so obviously I am doing something wrong here but don't know what especially.
Any help is highly appreciated.
In the end I managed successfully to connect to PC. The issue turned out to be in the NtlmPasswordAuthentication(); constructor.
So, instead of this:
String user = Constants.username + ":" + Constants.password;
NtlmPasswordAuthentication auth = new NtlmPasswordAuthentication(user);
I changed to this:
NtlmPasswordAuthentication auth = new NtlmPasswordAuthentication("",
Constants.username, Constants.password);
I don't know why, perhaps it's because of ":" special character, perhaps because of Android, but passing an empty domain name, the user name, and password separately to the constructor, solved the issue.
Since some people will get to this topic if they got a similar problem with android and JCIFS,
these are other common problems when trying to make it work:
*Put the .jar specifically in /libs folder of your android project (not just via "build path")
*Be sure that your project has internet permission What permission do I need to access Internet from an android application?
*Also be sure that your JCIFS code is running in a separate thread from the UI (in other words, use AsyncTask class) how to use method in AsyncTask in android?
*Code:
protected String doInBackground(String... params) {
SmbFile[] domains;
String username = USERNAME;
String password = PASSWORD;
NtlmPasswordAuthentication auth = new NtlmPasswordAuthentication("",
username, password);
try {
SmbFile sm = new SmbFile(SMB_URL, auth);
domains = sm.listFiles();
for (int i = 0; i < domains.length; i++) {
SmbFile[] servers = domains[i].listFiles();
for (int j = 0; j < servers.length; j++) {
Log.w(" Files ", "\t"+servers[j]);
}
}
} catch (SmbException e) {
e.printStackTrace();
} catch (MalformedURLException e) {
e.printStackTrace();
}
return "";
}
these were the problems i encounter while trying to make work JCIFS on android, hope to help anyone, regards.
maybe i can help other people too.
I had the problem that i used thread.run() instead of thread.start() to execute the Smb-Code in a Runnable. I searched a lot of time for an answer but nothing fixed my problem.
But then a friend explained me the different between thread.run() and thread.start():
run(): Execute the Methode (for example the run() Methode of a Runnable) like a normal Method (synchronous)
start(): Start the Thread with the Runnable in an own task (asynchronous)
And for Smb you need a asynchronous Thread. Because of this you need to call thread.start()!
Maybe someone make the same mistake as i did.

Java example of how to log in to Google App Engine with a Facebook account using OAuth

I searched a lot, read many blogs, articles, tutorials, but until now did not get a working example of using a Facebook account to log in to my application.
I know that I have to use OAuth, get tokens, authorizations, etc...
Can anyone share an example?
Here is how I do it on App Engine:
Step 1) Register an "app" on Facebook (cf. https://developers.facebook.com/ ). You give Facebook a name for the app and a url. The url you register is the url to the page (jsp or servlet) that you want to handle the login. From the registration you get two strings, an "app ID" and an "app secret" (the latter being your password, do not give this out or write it in html).
For this example, let's say the url I register is "http://myappengineappid.appspot.com/signin_fb.do".
2) From a webpage, say with a button, you redirect the user to the following url on Facebook, substituting your app id for "myfacebookappid" in the below example. You also have to choose which permissions (or "scopes") you want the ask the user (cf. https://developers.facebook.com/docs/reference/api/permissions/ ). In the example I ask for access to the user's email only.
(A useful thing to know is that you can also pass along an optional string that will be returned unchanged in the "state" parameter. For instance, I pass the user's datastore key, so I can retrieve the user when Facebook passes the key back to me. I do not do this in the example.)
Here is a jsp snippet:
<%#page import="java.net.URLEncoder" %>
<%
String fbURL = "http://www.facebook.com/dialog/oauth?client_id=myfacebookappid&redirect_uri=" + URLEncoder.encode("http://myappengineappid.appspot.com/signin_fb.do") + "&scope=email";
%>
<img src="/img/facebook.png" border="0" />
3) Your user will be forwarded to Facebook, and asked to approve the permissions you ask for. Then, the user will be redirected back to the url you have registered. In this example, this is "http://myappengineappid.appspot.com/signin_fb.do" which in my web.xml maps to the following servlet:
import org.json.JSONObject;
import org.json.JSONException;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class SignInFB extends HttpServlet {
public void service(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
String code = req.getParameter("code");
if (code == null || code.equals("")) {
// an error occurred, handle this
}
String token = null;
try {
String g = "https://graph.facebook.com/oauth/access_token?client_id=myfacebookappid&redirect_uri=" + URLEncoder.encode("http://myappengineappid.appspot.com/signin_fb.do", "UTF-8") + "&client_secret=myfacebookappsecret&code=" + code;
URL u = new URL(g);
URLConnection c = u.openConnection();
BufferedReader in = new BufferedReader(new InputStreamReader(c.getInputStream()));
String inputLine;
StringBuffer b = new StringBuffer();
while ((inputLine = in.readLine()) != null)
b.append(inputLine + "\n");
in.close();
token = b.toString();
if (token.startsWith("{"))
throw new Exception("error on requesting token: " + token + " with code: " + code);
} catch (Exception e) {
// an error occurred, handle this
}
String graph = null;
try {
String g = "https://graph.facebook.com/me?" + token;
URL u = new URL(g);
URLConnection c = u.openConnection();
BufferedReader in = new BufferedReader(new InputStreamReader(c.getInputStream()));
String inputLine;
StringBuffer b = new StringBuffer();
while ((inputLine = in.readLine()) != null)
b.append(inputLine + "\n");
in.close();
graph = b.toString();
} catch (Exception e) {
// an error occurred, handle this
}
String facebookId;
String firstName;
String middleNames;
String lastName;
String email;
Gender gender;
try {
JSONObject json = new JSONObject(graph);
facebookId = json.getString("id");
firstName = json.getString("first_name");
if (json.has("middle_name"))
middleNames = json.getString("middle_name");
else
middleNames = null;
if (middleNames != null && middleNames.equals(""))
middleNames = null;
lastName = json.getString("last_name");
email = json.getString("email");
if (json.has("gender")) {
String g = json.getString("gender");
if (g.equalsIgnoreCase("female"))
gender = Gender.FEMALE;
else if (g.equalsIgnoreCase("male"))
gender = Gender.MALE;
else
gender = Gender.UNKNOWN;
} else {
gender = Gender.UNKNOWN;
}
} catch (JSONException e) {
// an error occurred, handle this
}
...
I have removed error handling code, as you may want to handle it differently than I do. (Also, "Gender" is of course a class that I have defined.) At this point, you can use the data for whatever you want, like registering a new user or look for an existing user to log in. Note that the "myfacebookappsecret" string should of course be your app secret from Facebook.
You will need the "org.json" package to use this code, which you can find at: http://json.org/java/ (just take the .java files and add them to your code in an org/json folder structure).
I hope this helps. If anything is unclear, please do comment, and I will update the answer.
Ex animo, - Alexander.
****UPDATE****
I want to add a few tidbits of information, my apologies if some of this seems a bit excessive.
To be able to log in a user by his/her Facebook account, you need to know which user in the datastore we are talking about. If it's a new user, easy, create a new user object (with a field called "facebookId", or whatever you want to call it, whose value you get from Facebook), persist it in the datastore and log the user in.
If the user exist, you need to have the field with the facebookId. When the user is redirected from Facebook, you can grab the facebookId, and look in the datastore to find the user you want to log in.
If you already have users, you will need to let them log in the way you usually do, so you know who they are, then send them to Facebook, get the facebookId back and update their user object. This way, they can log in using Facebook the next time.
Another small note: The user will be presented with a screen on Facebook asking to allow your app access to whatever scopes you ask for, there is no way around this (the less scopes you ask for, the less intrusive it seems, though). However, this only happens the first time a user is redirected (unless you ask for more scopes later, then it'll ask again).
You can try face4j https://github.com/nischal/face4j/wiki . We've used it on our product http://grabinbox.com and have open sourced it for anyone to use. It works well on GAE.
There is an example on the wiki which should help you integrate login with facebook in a few minutes.
face4j makes use of oAuth 2.0 and the facebook graph API.
I had a lot of difficulty when trying to implement the OAuth signing myself. I spent a lot of time trying to debug an issue with my tokens not actually getting authorized - a common problem apparently. Unfortunately, none of the solutions worked for me so I ended up just using Scribe, a nifty Java OAuth library that has the added benefit of supporting other providers besides for Facebook (e.g. Google, Twitter, etc.)
You can take a look at LeanEngine, the server part: https://github.com/leanengine/LeanEngine-Server/tree/master/lean-server-lib/src/main/java/com/leanengine/server/auth
Check facebook's java APIs.
Other examples: http://code.google.com/p/facebook-java-api/wiki/Examples

Categories

Resources