I plan to have a server program fetching my dropbox account access token and pass to
client program to uplaod to my dropbox folder. Client does not need DB account or login and is able to send file to my DB folder (thus NOT using OAuth ...). Something similar to:
this
and this
but without user upload to server first, i.e., once user get the access token, they upload directly to DB.
I've tried to use Apache httpclient 4.3 to simulate a browser to perform getting request token, sending login-info to get acces token, but get stuck on upload the file via post to a form. Error is HTTP 400 Bad Request ...
executing request:GET https://www.dropbox.com/login HTTP/1.1
----------------------------------------
HTTP/1.1 200 OK
Request Token: moiejtzdLqTA_0sh3gQyNZAI
executing request:POST https://www.dropbox.com/login HTTP/1.1
----------------------------------------
HTTP/1.1 200 OK
Access Token: 5Ot52QKDbDPSsL1ApU4MIapJ
executing request:POST https://dl-web.dropbox.com/upload?
name=sample.jpg&dest=upload&cookie_t=5Ot52QKDbDP....SsJ&t=5Ot5...apJ HTTP/1.1
----------------------------------------
HTTP/1.1 400 Bad Request
I used Firefox LiveHttpHeader to capture the headers as I do the login and upload file, and saw the post to file upload actually is doing this (and reflect in the code):
https://dl-web.dropbox.com/chunked_upload?
name=tmp1.jpg
&chunk=0
&chunks=1
&bjar=W3sic2Vzc1..............Q%253D%253D
&blid=AAAw4tn................2cDxA
&cookie_t=32yq........nw6c34o
&dest=
&t=32yqVof........c34o
&reported_total_size=5611
&upload_id=1BKGRRP5TpCEjcWSu5tmpQ
&offset=0
So apparrently I missed some param but can't figure out what. The access token seems to be valid as I can see my account info in the return from a httpclinet post to https://www.dropbox.com/home, but the upload simply not working. Anyone has similar experience and getting HTTP 400 error ? .... Many Thanks !
Some code as below:
Constructor and main():
// constructor ...
public HttpClientExample() {
gcookies = new BasicCookieStore();
globalConfig = RequestConfig.custom()
.setCookieSpec(CookieSpecs.BEST_MATCH)
.build();
// Create local HTTP context
ghttpContext = HttpClientContext.create();
ghttpContext.setCookieStore(gcookies);
//
redirectStrategy = new LaxRedirectStrategy(); // for http redirect ...
httpclient = HttpClients.custom()
.setDefaultRequestConfig(this.globalConfig)
.setDefaultCookieStore(this.gcookies)
.setRedirectStrategy(redirectStrategy)
.build();
} // constructor ...
public static void main(String[] args) throws Exception {
HttpClientExample myhttp = new HttpClientExample();
try {
this.localConfig = RequestConfig.copy(this.globalConfig)
.setCookieSpec(CookieSpecs.BROWSER_COMPATIBILITY)
.build();
String requestToken = this.getRequestToken(httpclient, loginurl);
theAccessToken = this.postForAccessToken(requestToken, loginurl);
String localFileTopassIn = this.localPath ;
this.postToUpload(httpclient, this.theAccessToken, localFileTopassIn , this.dropboxFolderOnlyName);
}
}
Get the request token:
private String getRequestToken(HttpClient client, String theURL) throws Exception {
HttpGet httpget = new HttpGet(theURL);
httpget.setConfig(localConfig);
httpget.setHeader("Connection", "keep-alive");
System.out.println("\nexecuting request:" + httpget.getRequestLine());
// Create a custom response handler
ResponseHandler responseHandler = new ResponseHandler() {
public String handleResponse(final HttpResponse response)
throws ClientProtocolException, IOException {
int status = response.getStatusLine().getStatusCode();
if (status >= 200 ) { // && status cookies = gcookies.getCookies();
for (Cookie aCookie: cookies) {
String cookieName = aCookie.getName();
if ( !(cookieName.lastIndexOf(gvcString) == -1) ) {
gvc = aCookie.getValue();
} else if ( !(cookieName.lastIndexOf(tString) == -1) ) {
requestToken = aCookie.getValue();
}
}
System.out.println("Request Token: " + requestToken );
return requestToken;
}
postForAccessToken:
private String postForAccessToken(HttpClient client, String requestToken, String theURL) throws Exception{
/*
* Send a post together with request token and my login to get accessToken ...
*/
HttpPost httppost = new HttpPost(theURL); // loginurl);
httppost.setConfig(localConfig);
ghttpContext.setCookieStore(gcookies);
List params = new LinkedList();
params.add(new BasicNameValuePair("login_email", myemail));
params.add(new BasicNameValuePair("login_password", mypasswd));
params.add(new BasicNameValuePair("t", requestToken));
HttpEntity postentity = new UrlEncodedFormEntity(params);
httppost.setEntity(postentity);
System.out.println("\nexecuting request:" + httppost.getRequestLine());
// Create a custom response handler
ResponseHandler responseHandler = new ResponseHandler() {
public String handleResponse(final HttpResponse response)
throws ClientProtocolException, IOException {
int status = response.getStatusLine().getStatusCode();
if (status >= 200 ) { // && status cookies = gcookies.getCookies();
for (Cookie aCookie: cookies) {
String cookieName = aCookie.getName();
if ( !(cookieName.lastIndexOf(tString) == -1) ) {
theAccessToken = aCookie.getValue();
}
}
System.out.println("Access Token: " + theAccessToken );
return theAccessToken;
}
postToUpload:
private String postToUpload(HttpClient client, String accessToken, String localFileInfo, String destPath) throws Exception{
String bjarString = "bjar";
String blidString = "blid";
String bjar=null;
String blid=null;
List cookies = gcookies.getCookies();
for (Cookie aCookie: cookies) {
String cookieName = aCookie.getName();
if ( !(cookieName.lastIndexOf(bjarString) == -1) ) {
bjar = aCookie.getValue();
} else if ( !(cookieName.lastIndexOf(blidString) == -1) ) {
blid = aCookie.getValue();
}
}
String[] fileNameArry = localFileInfo.split("(\\\\|/)");
String filename = fileNameArry[fileNameArry.length - 1]; // get the last part ...
URI uri = new URIBuilder()
.setScheme("https")
.setHost("dl-web.dropbox.com")
.setPath("/upload")
.setParameter("name", filename)
.setParameter("dest", destPath)
.setParameter("cookie_t", accessToken)
.setParameter("t", accessToken)
.build();
HttpPost httppost = new HttpPost(uri);
httppost.setConfig(localConfig);
ghttpContext.setCookieStore(gcookies);
FileBody bin = new FileBody(new File(localFileInfo));
StringBody comment = new StringBody("A binary file of some kind", ContentType.DEFAULT_BINARY);
HttpEntity reqEntity = MultipartEntityBuilder.create()
.addPart("bin", bin)
.addPart("comment", comment)
.build();
httppost.setEntity(reqEntity);
// add header
httppost.setHeader("Host", "www.dropbox.com");
httppost.setHeader("User-Agent", USER_AGENT);
httppost.setHeader("Accept",
"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
httppost.setHeader("Connection", "keep-alive");
httppost.setHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
httppost.setHeader("Pragma", "no-cache");
httppost.setHeader("Cache-Control", "no-cache");
// add entity
System.out.println("\nexecuting request:" + httppost.getRequestLine());
// Create a custom response handler
ResponseHandler responseHandler = new ResponseHandler() {
public String handleResponse(final HttpResponse response)
throws ClientProtocolException, IOException {
int status = response.getStatusLine().getStatusCode();
if (status >= 200 ) { // && status
OAuth is the only way to use the Dropbox API. Once you have an OAuth access token (which you get by authenticating once, in this case with your account), you just need to do an HTTP PUT to https://api-content.dropbox.com/1/files_put/auto/<path> with the header Authorization: Bearer <token> and the contents of the file in the body.
Note that anyone who has your access token can also delete all your files, upload their personal DVD collection, etc. So it's not recommended that you share that access token.
There is files_get_temporary_upload_link:
Get a one-time use temporary upload link to upload a file to a Dropbox location.
This endpoint acts as a delayed upload. The returned temporary upload link may be used to make a POST request with the data to be uploaded. The upload will then be perfomed with the CommitInfo previously provided to get_temporary_upload_link but evaluated only upon consumption. Hence, errors stemming from invalid CommitInfo with respect to the state of the user's Dropbox will only be communicated at consumption time. Additionally, these errors are surfaced as generic HTTP 409 Conflict responses, potentially hiding issue details. The maximum temporary upload link duration is 4 hours. Upon consumption or expiration, a new link will have to be generated. Multiple links may exist for a specific upload path at any given time.
So you need to have an access token to call this function, but the uploader needs only the produced URL, without access to the rest of the Dropbox vault.
Related
The authentication process is not working now.(It was working earlier). By following the documentation I'm trying to get the access token from a refresh token. I successfully can get a access token. But it's not valid. I'm setting it as Bearer and send it in my GET request and it returns the following JSON
{"error":{"code":"accessDenied","message":"Access Denied"}}
Here is the code sample
String messageBody = "client_id=" + "9b1a6dbb-7e1f-41b5-b448-9f328169411e" + "&redirect_uri=" + returnURL + "&client_secret={cleindsecret}
+ "&refresh_token={refreshtoken}&grant_type=refresh_token";
RequestBody oAuthCodeRedeemBody = RequestBody.create(MediaType.parse("application/x-www-form-urlencoded"),
messageBody);
Request request = new Request.Builder().url("https://login.live.com/oauth20_token.srf")
.post(oAuthCodeRedeemBody).build();
String responseBody = null;
OkHttpClient client = new OkHttpClient();
client.setFollowRedirects(false);
Response response;
String accessToken = null;
try {
response = client.newCall(request).execute();
responseBody = response.body().string();
resp = (JSONObject) jsonParser.parse(responseBody);
} catch (IOException | ParseException e) {
e.printStackTrace();
}
accessToken = (String) resp.get("access_token");
I'm getting a Access Token here. But I can't use it to do any work.
Request request2 = new Request.Builder().url("https://api.onedrive.com/v1.0/drive/items/1ED8983F38E94F01!107/children").header("Authorization", "Bearer " + accessToken).get().build();
The response for the above code is returned as
{"error":{"code":"accessDenied","message":"Access Denied"}}
What is the reason here. Is the API returning me a invalid access token or is something wrong in my code?
Our application calls out-of-the-box Office 365 Management API to retrieve activities and events on files stored in SharePoint Online. However per our experiment, the application can’t seem to retrieve not enough logs.
Example: We upload 1000 files to document library in Sharepoint Online. We receive 8 subscriptiona. Each subscription, we only get maximum 100 logs. Total call API get logs to retrieve 600 logs. Not enough!
Here my code to get subscription
List<SubscriptionsContent> GetSubscriptionsContents(AuthenticationResult authenticationResult, ManagementAPI m, DateTime startDate, DateTime endDate, bool proxyRequired = false)
{
try
{
string jsonSubscription = string.Empty;
string url = string.Empty;
string logType = "Audit.SharePoint";
if (authenticationResult != null)
{
url = string.Format(UrlFormat, m.TenantId, string.Format("subscriptions/content?contentType={0}&startTime={1}&endTime={2}", logType, startDate.ToUniversalTime().ToString(DateFormat), endDate.ToUniversalTime().ToString(DateFormat)));
jsonSubscription = ExecuteRequest(url, HttpMethod.Get, authenticationResult);
//Log.Info("jsonSubscription:");
//Log.Info(jsonSubscription);
}
var listContent = Common.GetListSubscriptionsContent(jsonSubscription);
Log.Info("Common.GetListSubscriptionsContent(jsonSubscription); Count: " + (listContent != null ? listContent.Count.ToString() : "IS NULL"));
return listContent;
}
catch (Exception ex)
{
Log.Error(ex);
return new List<SubscriptionsContent>();
}
}
Here my code to execute Request
public string ExecuteRequest(string url, HttpMethod method, AuthenticationResult token)
{
var responseStr = "";
try
{
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpRequestMessage request = new HttpRequestMessage(method, url);
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token.AccessToken);
HttpResponseMessage response = client.SendAsync(request).Result;
Log.Info("ExecuteRequest(string url, HttpMethod method, AuthenticationResult token): response.StatusCode: " + response.StatusCode + " ; response.ReasonPhrase: " + response.ReasonPhrase + " ; response.RequestMessage: " + response.RequestMessage);
if (response.IsSuccessStatusCode)
{
responseStr = response.Content.ReadAsStringAsync().Result;
}
}
catch (Exception ex)
{
Log.Error(ex);
}
return responseStr;
}
Here my code to get audit log from each subscription
List<AuditLog> listAudit = new List<AuditLog>();
foreach (var item in listSubscription)
{
var jsonAudit = ExecuteRequest(item.ContentUri.ToString(), HttpMethod.Get, authenticationResult);
if (string.IsNullOrEmpty(jsonAudit))
continue;
var listAuditLog = Common.GetListAuditLog(jsonAudit);
}
Here my code to parser JsonString
public static List<AuditLog> GetListAuditLog(string jsonString)
{
try
{
return JsonConvert.DeserializeObject<List<AuditLog>>(jsonString);
}
catch (Exception ex)
{
Log.Error("public static List<AuditLog> GetListAuditLog(string jsonString)", ex.InnerException);
return new List<AuditLog>();
}
}
I think that you need to use the pagination header.
If the amount of data is too big, the API will return a header entry named NextPageUrl containing an address to be used to request the next page of results. This link (representing the query) will be available for 24 hours.
Ex.
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
NextPageUrl:https://manage.office.com/api/v1/{tenant_id}/activity/feed/subscriptions/content?contentType=Audit.SharePoint&startTime=2015-10-01&endTime=2015-10-02&nextPage=2015101900R022885001761
So, if the response contains this header entry, just use the value of NextPageUrl to request more data.
Repeat the process until this header entry doesn't exists anymore.
You can find more information in the Office 365 Management API reference
Today i wanted to switch from GCM to FCM so i set up everything needed and wanted to implement the server side code. I used the gcm4j library and changed it so that the adress goes to https://fcm.googleapis.com/fcm/send.
So im doing the following:
FCM fcm = new FCMDefault(new FCMConfig().withKey(FCMGlobals.FCM_API_KEY));
FCMRequest request = new FCMRequest().withRegistrationId(android.getRegistration())
// .withCollapseKey(collapseKey)
.withDelayWhileIdle(true)
.withDataItem(FCMGlobals.FCM_PARAM_CODE, code)
.withDataItem(FCMGlobals.FCM_PARAM_USER_ID, "" + user.getId())
.withDataItem(FCMGlobals.FCM_PARAM_ADDITION, "" + addition);
ListenableFuture<FCMResponse> responseFuture = fcm.send(request);
Futures.addCallback(responseFuture, new FutureCallback<FCMResponse>() {
public void onFailure(Throwable t) {
log.error(t);
}
#Override
public void onSuccess(FCMResponse response) {
log.info(response.toString());
}
});
The implementation for that is:
protected FCMResponse executeRequest(FCMRequest request) throws IOException {
byte[] content = this.objectMapper.writeValueAsBytes(request);
HttpURLConnection conn = this.connectionFactory.open(this.fcmUrl);
conn.setRequestMethod("POST");
conn.addRequestProperty("Authorization", getAuthorization(request));
conn.addRequestProperty("Content-Type", "application/json");
conn.setDoOutput(true);
conn.setFixedLengthStreamingMode(content.length);
LoggerFactory.getLogger("FCMDefaultAbstract").info("Authorization: " + conn.getRequestProperty("Authorization"));
LoggerFactory.getLogger("FCMDefaultAbstract").info("Content-Type: " + conn.getRequestProperty("Content-Type"));
LoggerFactory.getLogger("FCMDefaultAbstract").info("send: " + new String(content));
try (OutputStream outputStream = conn.getOutputStream()) {
IOUtils.write(content, outputStream);
} catch (Exception e) {
throw new FCMNetworkException("Error sending HTTP request to FCM", e);
}
FCMResponse response;
try (InputStream inputStream = conn.getInputStream()) {
response = this.objectMapper.readValue(IOUtils.toByteArray(inputStream), FCMResponse.class);
} catch (IOException e) {
try (InputStream inputStreamError = conn.getErrorStream()) {
String str = inputStreamError != null ? IOUtils.toString(inputStreamError) : "No error details provided";
int responseCode = conn.getResponseCode();
if (responseCode < 500) {
throw new FCMNetworkException(conn.getResponseCode(), str.trim(), e);
} else {
throw new FCMNetworkException(conn.getResponseCode(), str.trim(), checkForRetryInResponse(conn), e);
}
}
}
response.setRequest(request);
response.setRetryAfter(checkForRetryInResponse(conn));
Iterator<String> iteratorId = request.getRegistrationIds().iterator();
Iterator<FCMResult> iteratorResponse = response.getResults().iterator();
while (iteratorId.hasNext() && iteratorResponse.hasNext()) {
iteratorResponse.next().setRequestedRegistrationId(iteratorId.next());
}
if (iteratorId.hasNext()) {
LOG.warn("Protocol error: Less results than requested registation IDs");
}
if (iteratorResponse.hasNext()) {
LOG.warn("Protocol error: More results than requested registation IDs");
}
return response;
}
Here the log output:
FCMDefaultAbstract Authorization: null
FCMDefaultAbstract Content-Type:application/json
FCMDefaultAbstract send: {"registration_ids":["dMpvzp*************************************2lRsSl_5lFET2"],"data":{"CODE":"201","USER_ID":"1","ADDITION":"1468083549493"},"delay_while_idle":true}
FCM FCMNetworkException: HTTP 401: No error details provided
The Authorization header is not null in fact. it is correctly set with my FCM API Key. Only the HTTPUrlConnection implementation says to return null if someone trys to access Authorization key.
As you can see i am not able to connect with FCM. The Code 401 means that authentication failed.
What could be the problem here?
Check that you are using a server type API-KEY, and not a client or browser API-KEY.
If you are using Firebase you can find the API-KEY in
Project Settings > Cloud Messaging
If you are using cloud console, or you are not sure which key you are using,
you can generate a new key through through https://console.cloud.google.com
Quoting the documentation
https://firebase.google.com/docs/cloud-messaging/concept-options#credentials
Server key: A server key that authorizes your app server for access to
Google services, including sending messages via Firebase Cloud
Messaging. [...]
Important: Do not include the server key anywhere in your client code.
Also, make sure to use only server keys to authorize your app server.
Android, iOS, and browser keys are rejected by FCM.
According to this documentation, process of receiving OAuth access token is straightforward. I would like to see a list of all available API endpoints that is ready to accept OAuth 2.0 access token. But for my current needs i would like to somehow receive username and email of a user using OAuth 2.0 access token.
I successfully can receive, for example, data from this endpoint:
https://www.google.com/m8/feeds/contacts/default/full
But unable to receive data from this endpoint:
https://www.googleapis.com/userinfo/email
I tried both header-base and querystring-base approaches of passing single access token. Here is a header i tried:
Authorization: OAuth My_ACCESS_TOKEN
And I even tried OAuth 1.0 version of Authorization header, but... in OAuth 2.0 we do not have secret access token, for instance. Google use bearer tokens in his implementation of OAuth 2.0, so no additional credentials are required.
Anyone successfully received username and email using Google OAuth 2.0?
I found the answer I was looking for. I had to convert PHP to MVC, but pretty easy:
http://codecri.me/case/430/get-a-users-google-email-address-via-oauth2-in-php/
My MVC Login sandbox code looks like the following.
(using JSON.Net http://json.codeplex.com/)
public ActionResult Login()
{
string url = "https://accounts.google.com/o/oauth2/auth?";
url += "client_id=<google-clientid>";
url += "&redirect_uri=" +
// Development Server :P
HttpUtility.UrlEncode("http://localhost:61857/Account/OAuthVerify");
url += "&scope=";
url += HttpUtility.UrlEncode("http://www.google.com/calendar/feeds/ ");
url += HttpUtility.UrlEncode("http://www.google.com/m8/feeds/ ");
url += HttpUtility.UrlEncode("http://docs.google.com/feeds/ ");
url += HttpUtility.UrlEncode("https://mail.google.com/mail/feed/atom ");
url += HttpUtility.UrlEncode("https://www.googleapis.com/auth/userinfo.email ");
url += HttpUtility.UrlEncode("https://www.googleapis.com/auth/userinfo.profile ");
url += "&response_type=code";
return new RedirectResult(url);
}
The code returned is proof of Authorization token from the user, which then needs to be turn into a Authentication (accessToken) to access resources.
My MVC OAuthVerify then looks like:
public ActionResult AgentVerify(string code)
{
JObject json;
if (!string.IsNullOrWhiteSpace(code))
{
NameValueCollection postData = new NameValueCollection();
postData.Add("code", code);
postData.Add("client_id", "<google-clientid>");
postData.Add("client_secret", "<google-client-secret>");
postData.Add("redirect_uri", "http://localhost:61857/Account/OAuthVerify");
postData.Add("grant_type", "authorization_code");
try
{
json = JObject.Parse(
HttpClient.PostUrl(
new Uri("https://accounts.google.com/o/oauth2/token"), postData));
string accessToken = json["access_token"].ToString();
string refreshToken = json["refresh_token"].ToString();
bool isBearer =
string.Compare(json["token_type"].ToString(),
"Bearer",
true,
CultureInfo.CurrentCulture) == 0;
if (isBearer)
{
json = JObject.Parse(
HttpClient.GetUrl(
new Uri("https://www.googleapis.com/oauth2/v1/userinfo?alt=json"),
accessToken));
string userEmail = json["email"].ToString();
}
return View("LoginGood");
}
catch (Exception ex)
{
ErrorSignal.FromCurrentContext().Raise(ex); //ELMAH
}
}
return View("LoginBad");
}
To complete how everything works, I've included the HttpClient utility I created in case anyone needed it.
public class HttpClient
{
public static string GetUrl(Uri url, string OAuth)
{
string result = string.Empty;
using (WebClient httpClient = new WebClient())
{
httpClient.Headers.Add("Authorization","OAuth " + OAuth);
result = httpClient.DownloadString(url.AbsoluteUri);
}
return result;
}
public static string PostUrl(Uri url, NameValueCollection formData)
{
string result = string.Empty;
using (WebClient httpClient = new WebClient())
{
byte[] bytes = httpClient.UploadValues(url.AbsoluteUri, "POST", formData);
result = Encoding.UTF8.GetString(bytes);
}
return result;
}
}
Again, this is test code just to get it to function, I do not recommend using this as-is in a production environment.
try this:
curl -k https://www.googleapis.com/userinfo/email -H "Authorization: OAuth 1/g5_039aCIAfEBuL7OCyB31n1URYU5tUIDudiWKuxN1o"
output: email=name#gmail.com&isVerified=tru
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).