picasawebservice java authentication access denied - google-oauth

My previously working picasawebservice code failed when Google switched to the OAuth 2 authentication.
I have modified the code to use a Goodle credential for which I needed to set up a Service Account.
Although no errors are returned when I add the credential to the PicasawebService object I cannot add any photos to my album.
I have obtained a list of albums using the url https://picasaweb.google.com/data/feed/api/user/xxx?kind=album but it only returns the public Profile Album, not the other albums on the account, also when I use the album id returned by the feed I get an "Access forbidden" error when I try to insert a photo. (xxx - I have used both the user id and the email address for the account and get the same result in each case).
I have been able to establish the alubum ids for the private albums on the account but using these also failed when attempting an insert.
The code is
String emailAddress = "-- the email address from the Google Developers console for the credential --";
JsonFactory JSON_FACTORY = JacksonFactory.getDefaultInstance();
GoogleCredential credential = null;
try {
HttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport();
String[] SCOPESArray = {"https://picasaweb.google.com/data","http://picasaweb.google.com/data/feed/api"};
final List<String> SCOPES = Arrays.asList(SCOPESArray);
credential = new GoogleCredential.Builder()
.setTransport(httpTransport)
.setJsonFactory(JSON_FACTORY)
.setServiceAccountId(emailAddress)
.setServiceAccountPrivateKeyFromP12File(new File("-- the p12 key file --"))
.setServiceAccountScopes(SCOPES)
.build();
} catch (GeneralSecurityException ex) {
logger.error("processUpload: Error getting Google credential " + accountBean.getZuzzAccountId() + " - " + accountBean.getAccountTitle() + " - " + ex.toString());
uploadMessage = "Error getting a connection to the photo store - please see the administratior";
return;
}
credential.refreshToken();
String accessToken = credential.getAccessToken();
PicasawebService myService = new PicasawebService("Zuzz-ZuzzClub-1.2");
myService.setOAuth2Credentials(credential);
URL albumPostUrl = null;
try {
albumPostUrl = new URL("https://picasaweb.google.com/data/feed/api/user/-- my user id --/albumid/-- album id returned from feed --");
} catch (MalformedURLException ex) {
logger.error("processUpload: Error getting album post url for account " + accountBean.getZuzzAccountId() + " - " + accountBean.getAccountTitle() + " - " + ex.toString());
uploadMessage = "Error getting a connection to the photo store - please see the administratior";
return;
}
PhotoEntry myPhoto = new PhotoEntry();
myPhoto.setTitle(new PlainTextConstruct(fileName));
myPhoto.setDescription(new PlainTextConstruct(months.get(Integer.valueOf(editionMonth).intValue()) + " " + editionYear));
myPhoto.setClient("ZuzzClub");
MediaStreamSource myMedia = null;
myMedia = new MediaStreamSource(imageInStream,"image/jpeg");
if (myMedia == null) {
logger.error("processUpload: Error generating the thumbnail photo - null media source for account " + accountBean.getZuzzAccountId() + " - " + accountBean.getAccountTitle());
uploadMessage = "Error generating the thumbnail photo - please see the administratior";
return;
}
myPhoto.setMediaSource(myMedia);
thumbNailUrl = null;
try {
PhotoEntry returnedPhoto = myService.insert(albumPostUrl, myPhoto);
ArrayList<MediaContent> mediaContent = (ArrayList<MediaContent>) returnedPhoto.getMediaContents();
thumbNailUrl = mediaContent.get(0).getUrl();
} catch (IOException ex) {
logger.error("processUpload: Error adding photo to Photo store for account " + accountBean.getZuzzAccountId() + " - " + accountBean.getAccountTitle() + " - " + ex.toString());
uploadMessage = "Error generating the thumbnail photo - please see the administratior";
return;
} catch (ServiceException ex) {
logger.error("processUpload: Error adding photo to Photo store for account " + accountBean.getZuzzAccountId() + " - " + accountBean.getAccountTitle() + " - " + ex.toString());
uploadMessage = "Error generating the thumbnail photo - please see the administratior";
return;
} finally {
imageInStream.close();
}
The problem appears to be that the authentication has not granted permission to perform the insert, however the service account is set to "Can edit" in the Google Developers Console.
Is there a way of finding out what permissions the service has after the credential has been applied?
Has anyone managed to add photos to a Picasa album after the authentication change?

Related

Send document to zoom chat via java program

I'm trying to send a file using zoom api, and I have a OAuth server-to-server authentication with /chat_message:write:admin in my app scope and I have tested simple message without problems. I already have a token, my ID and my recipient's ID.
My program runs and returns error 405 method not allowed.
I choose to send label.pdf file.
Zoom documentation page is: link to zoom api send document
private static final String API_ENDPOINT = "https://api.zoom.us/v2/chat/users/";
// Create API URL
URL url = new URL(API_ENDPOINT + userId + "/messages/files");
// Open connection and set request properties
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("POST");
conn.setRequestProperty("Authorization", "Bearer " + token);
conn.setRequestProperty("Content-Type", "multipart/form-data; boundary=boundary");
byte[] pdfData = Files.readAllBytes(new File(filePath).toPath());
String boundary = "boundary";
String delimiter = "--" + boundary + "\r\n";
StringBuilder builder = new StringBuilder();
builder.append(delimiter);
builder.append("Content-Disposition: form-data; name=\"to_contact\"\r\n\r\n");
builder.append(toContact+"\r\n");
builder.append(delimiter);
builder.append("Content-Disposition: form-data; name=\"files\"; filename=\"label\"\r\n");
builder.append("Content-Type: application/pdf\r\n");
builder.append("\r\n");
builder.append(new String(pdfData, "ISO-8859-1"));
builder.append("\r\n");
builder.append("--" + boundary + "--");
conn.setDoOutput(true);
String multipartData = builder.toString();
System.out.println(multipartData);
conn.getOutputStream().write(multipartData.getBytes("UTF-8"));
// Send request and get response code and message
conn.connect();
int responseCode = conn.getResponseCode();
String responseMessage = conn.getResponseMessage();
// Check if response is successful
if (Arrays.asList(RESPONSE_CODE).contains(Integer.toString(responseCode))) {
System.out.println("File sent successfully!");
System.out.println("Response code: " + responseCode);
System.out.println("Response message: " + responseMessage);
} else {
System.out.println("Error sending file:");
System.out.println("Response code: " + responseCode);
System.out.println("Response message: " + responseMessage);
}
// Close connection
conn.disconnect();
Can anyone suggest me what's wrong?

Is there any way to message on whatsapp without opening the application

I've been searching for the solution to send the message on whatsapp from the Application or via REST-APIs without opening it.
As I have mentioned below the code will validate for the Whatsapp-type installed in device and then it will send it to user but in this case it launch the whatsapp.
private void launchWhatsapp(String msg) {
try {
boolean installed2 = obj.appInstalledOrNot("com.whatsapp.w4b");
if (installed2) try {
Intent sendIntent = new Intent("android.intent.action.MAIN");
sendIntent.setAction(Intent.ACTION_VIEW);
sendIntent.setPackage("com.whatsapp.w4b");
String url = "https://api.whatsapp.com/send?" +
"phone=" + PhoneNumberUtils.stripSeparators(Cust_Phone_Code + " " + getIntent().getStringExtra("Cust_Mob")) +
"&text=" + msg;
sendIntent.setData(Uri.parse(url));
if (sendIntent.resolveActivity(this.getPackageManager()) != null) {
startActivityForResult(sendIntent, 104);
}
} catch (Exception e) {
e.printStackTrace();
}
else {
boolean installed = obj.appInstalledOrNot("com.whatsapp");
if (installed) {
Intent sendIntent = new Intent("android.intent.action.MAIN");
sendIntent.setAction(Intent.ACTION_VIEW);
sendIntent.setPackage("com.whatsapp");
String url = "https://api.whatsapp.com/send?" +
"phone=" + PhoneNumberUtils.stripSeparators(Cust_Phone_Code + " " + getIntent().getStringExtra("Cust_Mob")) +
"&text=" + msg;
sendIntent.setData(Uri.parse(url));
if (sendIntent.resolveActivity(this.getPackageManager()) != null) {
startActivityForResult(sendIntent, 104);
}
} else {
Toast.makeText(InvoiceReport.this, "Whatsapp not available", Toast.LENGTH_SHORT).show();
}
}
} catch (Exception e) {
//Log.e("Error", "ERROR_OPEN_MESSANGER"+e.toString());
}
}
I am expecting if anyone click on the browser on send message then this redirect to whatsapp application.

Session Variables Lost after ReDirect

I have an MVC site that is using membership providers for authenticating against multiple domains.
I am using SESSION to store the displayName of my user that I then display in my _Layout.cshtml
This all works perfectly on my localhost, but when I deploy my app to VM/Server the SESSION is null and i get Object not set to an instance of an object and the error points to the line in my layout page where i display the full username. This happens after session timeout and user requests a new page and are required to login again.
Here is my Login method:
if (!ModelState.IsValid)
{
return View(model);
}
Session["UserName"] = "Unknown User";
Logger.Instance.Info("Setting username to unknown user");
var msg = string.Empty;
var user = _userSvc.GetLoginUserData(model.Username, out msg);
if (!string.IsNullOrEmpty(msg))
{
Logger.Instance.Info("getting user info but error returned: "+msg);
ModelState.AddModelError("", msg);
return View(model);
}
Logger.Instance.Info("User was found "+user.EMAIL);
foreach (MembershipProvider provider in Membership.Providers)
{
var username = user.LEGACY_USERNAME;
if (provider.Name == "ADENTMembershipProvider") username = user.ENT_USERNAME;
try
{
Logger.Instance.Info("Authenticating user "+username+" to "+provider.Name);
if (provider.ValidateUser(username, model.Password))
{
Session["UserName"] = user.FIRST_NAME + ' ' + user.LAST_NAME;
Logger.Instance.Info("User authenticated " + Session["UserName"]);
var authTicket = new FormsAuthenticationTicket(
1, // version
user.ID.ToString(), // user name
DateTime.Now, // created
DateTime.Now.AddMinutes(2), // expires
false, // persistent?
user.ROLE // can be used to store roles
);
string encryptedTicket = FormsAuthentication.Encrypt(authTicket);
var authCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket);
Response.Cookies.Add(authCookie);
if (returnUrl != null && returnUrl != "/")
{
Logger.Instance.Info("Redirecting user to " + returnUrl);
Response.Redirect(returnUrl);
}
else
{
return RedirectToAction("Index", "Home");
}
}
}
catch (Exception ex)
{
Logger.Instance.Error("Error authenticating user " + username + " to " + provider.Name, ex);
}
}
SynLogger.Instance.Info("User could not be authenticated " );
// User was not authenticated in any of the AD
ModelState.AddModelError("", "Invalid login attempt. The username or password provided is incorrect.");
return View(model);
Here is the line in my layout that is causing the issue when session times out and user re-logs in:
Hello #Html.Raw(Session["UserName"].ToString())
Not sure why it works on my development machine but not when I deploy to server.
Is there another way I can store the username other than SESSION so I can access it my layout page?

HTTP POST 400 . Bad request. Google Cloud storage XML API call to upload file

I am receiving this error code.
E/camera_classes.callHttpPostToSendFiles: exception message e
java.io.IOException: Server returned non-OK status: 400 message: Bad Request error stream : com.android.okhttp.internal.http.HttpTransport$FixedLengthInputStream#42353798at camera_classes.postMultipartEntity.finish(postMultipartEntity.java:161)
at camera_classes.callHttpPostToSendFiles.postData(callHttpPostToSendFiles.java:193)
at camera_classes.callHttpPostToSendFiles$1.doInBackground(callHttpPostToSendFiles.java:109)
at camera_classes.callHttpPostToSendFiles$1.doInBackground(callHttpPostToSendFiles.java:105)
at android.os.AsyncTask$2.call(AsyncTask.java:288)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
at java.lang.Thread.run(Thread.java:841)
The error is happening at
public List<String> finish() throws IOException {
List<String> response = new ArrayList<String>();
writer.append(LINE_FEED).flush();
writer.append("--" + boundary + "--").append(LINE_FEED);
writer.close();
// checks server's status code first
int status = httpConn.getResponseCode();
String server_message = httpConn.getResponseMessage();
if (status == HttpURLConnection.HTTP_OK) {
BufferedReader reader = new BufferedReader(new InputStreamReader(
httpConn.getInputStream()));
String line = null;
while ((line = reader.readLine()) != null) {
response.add(line);
}
reader.close();
httpConn.disconnect();
} else {
throw new IOException("Server returned non-OK status: " + status + " message: " + server_message + " error stream : " + httpConn.getErrorStream());
}
1) I am interested in getting more information on the error code (400 Bad Request) listed here, so I can understand what is causing the "400 Bad request" error. Can anyone help. I have tried all the available public methods - httpConn.getResponseMessage(), httpConn.getResponseCode() and httpConn.getErrorStream().
2) What does com.android.okhttp.internal.http.HttpTransport$FixedLengthInputStream#42353798 mean? This is the output of httpConn.getErrorStream().
I'm using an upload method for Google Cloud XML Api like below. About your second question, maybe it's related to use of method setFixedLengthStreamingMode from HttpUrlConnection, as I used in my function, where you have to put the length of file being uploaded:
URL url = new URL("www.urltoupload.com");
HttpURLConnection httpCon = (HttpURLConnection) url.openConnection();
httpCon.setDoOutput(true);
httpCon.setRequestMethod("PUT");
httpCon.setRequestProperty("Content-Type", Utils.getMimeType(path));
httpCon.setRequestProperty("Connection", "Keep-Alive");
httpCon.setFixedLengthStreamingMode((int) dest.length());
final DataOutputStream out = new DataOutputStream(httpCon.getOutputStream());
float bytesTotal = fileBeingUploaded.length();
int bytesRead;
byte buf[] = new byte[8192];
BufferedInputStream bufInput = new BufferedInputStream(new FileInputStream(dest));
while ((bytesRead = bufInput.read(buf)) != -1) {
out.write(buf, 0, bytesRead);
out.flush();
}
out.close();

Interaction with Lotus Connections

I need to get the data from some lotus connection site, for example user's status, from the other site. I try to setup a connection with lotus via java, e.g.
> server = "https://" + path + param + "&format=full";
> URL profiles_url = new URL(server);
> // Open the URL: throws exception if not found
> HttpURLConnection profiles_conn = HttpURLConnection)profiles_url.openConnection();
> profiles_conn.connect();
> // Process the Atom feed in the response content
> readResponse(profiles_url.openStream(),args[0]);
But I always get the Response: HTTP/1.1 401 Unauthorized
Please give me any suggestions?
I solved the authentication issue this way:
protected void doView(RenderRequest rRequest, RenderResponse rResponse) throws PortletException, IOException, UnavailableException {
try {
rResponse.setContentType("text/html");
URL url = new URL(
"https://xxx/activities/service/atom2/todos");
URLConnection con = url.openConnection();
con.setConnectTimeout(150000);
con.setReadTimeout(150000);
writeCookies(con, rRequest);
DO_SOMETHING (con.getInputStream());
} catch (Exception ex) {
ex.printStackTrace();
}
}
private String doesLTPATokenCookieExists(RenderRequest request) {
Cookie[] cookie = request.getCookies();
for (int i = 0; i < cookie.length; i++) {
System.out.println("Cookie Name " + cookie[i].getName());
if (cookie[i].getName().equals("LtpaToken"))
return cookie[i].getValue();
}
return null;
}
public URLConnection writeCookies(URLConnection urlConn,
RenderRequest request) {
String cookieString = "";
cookieString += "LtpaToken" + "=" + doesLTPATokenCookieExists(request) + "; ";
urlConn.setRequestProperty("Cookie", cookieString);
return urlConn;
}
You don't mention how you're authenticating, which is crucial. As the 401 error implies, Connections isn't treating your request as being authenticated. You need a valid Authenticator instance in there, but your code snippet suggests you haven't got that going, correct?
(As an aside, the Apache Abdera project is recommended when working with the Lotus Connections API).