ACCESS_DENIED Status from Places API - android-maps-v2

I'm developing an Android App that uses the Places API to retrieve information and displays it on a map. The initial request to retrieve to places fails with a ACCESS_DENIED status message from the HTTP request. Below is the code that I used to generate the request:
try {
HttpRequestFactory httpRequestFactory = createRequestFactory(HTTP_TRANSPORT);
HttpRequest request = httpRequestFactory
.buildGetRequest(new GenericUrl(PLACES_SEARCH_URL));
request.getUrl().put("key", API_KEY);
request.getUrl().put("location", _latitude + "," + _longitude);
request.getUrl().put("radius", _radius); // in meters
request.getUrl().put("sensor", "false");
if(types != null)
request.getUrl().put("types", types);
PlacesList list = request.execute().parseAs(PlacesList.class);
// Check log cat for places response status
Log.d("Places Status", "" + list.status);
return list;
In another Stackoverflow posting someone had suggested that the poster try the following to test their key:
Go to the api console here, then to SERVICES. Click Active services
tab and verify 'Places API' is turned ON. Click on the ? "try" link
next to it. It should create a proper URL with your key which should
work. Compare the link that you are trying against this URL for
differences.
I followed these instructions. Based on the fact that I received the following results when I clicked on the ? to "try" the link I suspect something is fundamentally wrong with the API Key independent of the code...otherwise I would think I would get a SUCCESS rather than REQUEST_DENIED:
{
"html_attributions" : [],
"results" : [],
"status" : "REQUEST_DENIED"
}
I obtained my key by entering the SHA1 of my debug certificate (which i obtained using Keytool with all the appropriate parameters...e.g, androiddebugkey....debug.keystore) followed by a ";" and the Package Name of the app.
Not sure what the problem is...I'm sure it's something simple but I'm not seeing it and I'm stuck. Thoughts?

I never received a response to this posting so ultimately I've resolved the problem by creating a brand new key under a new project name and I was at least able to retrieve Places from Google..I'm still having issues with populating maps but that could be a code issue.
I noticed that the key that I was using that gave me the ACCESS DENIED results had a title of: "Key for Android apps (with certificates)" and it had a label "Android apps:" listed just under the actual key. The key value is the SHA1 value ";" followed by the Package Name. Whereas the key I created under a new Project Name (Places API) that ultimately worked had a title of: "Key for browser apps (with referers)" and it had a label of "Referers:" and value of "Any referer allowed".
So there is definitely something different about these two keys. I'm not sure what I did differently when I generated the keys. I'd like to understand what I did to generate these two "different" types of keys so that I and perhaps others won't repeat my "mistake(s)".
There are many references to creating keys in the Google documentation. The fact that there are so many postings regarding problems with the keys tells me that the Google documentation is not very clear otherwise so many issues wouldn't exist on this topic.

Related

Neoj4 GCP error: "The requested URL /v1/documents:classifyText?key=apiKey was not found on this server"

I am trying to figure out how Neoj4 Desktop can be used to handel NLP usgin this blog. Everything was ok until the text classification moment:
CALL apoc.periodic.iterate("
// get all articles
MATCH (node:Article) RETURN node
","
// classify each article
CALL apoc.nlp.gcp.classify.graph(node, {
// we retrieve gcp api key from static value storage
key: apoc.static.get('gcp.apiKey'),
// node property that contains the text
nodeProperty: 'content',
write:true
}) YIELD graph RETURN distinct 'done'",
{batchSize:10})
Instead of returning categories, it returns "The requested URL /v1/documents:classifyText?key=apiKey was not found on this server" error
Maybe it is something with GCP credentials, but I have done everything as suggested.
Thanks for reading my blog post! :)
Please try the following command:
RETURN apoc.static.get('gcp.apiKey')
Does it return anything? It should return your google API key. If it doesn't work you can always just try to copy your API key into the query. On the other hand, if apoc.static.get works as intended, maybe try to Enable your Natural Language API in the google console. That could be one issue.

Connectwise REST API Implementation using python

In my application , I am going to use connectwise API , but I can't figure out how to call their API, like
How to connect
How to pass header (json data)
How to authentication (I have company id , public and private key)
How to make call and take response
I am Python guy
Thanks in advance
This question is quite broad, and you'll need to get familiar with something such as the Requests module if you aren't already.
Also, ConnectWise has a lot of documents at their developer site and registration is free and easy.
However I went through this journey myself over the last few weeks and learnt a lot so I'll share it with you.
Authentication
Authentication is done by creating an API user. In CW Manage you can create a member user with the API license class.
In ConnectWise Manage:
Go to System => Members
Go to the API Members tab.
Create a new API member that gives the API access to the areas that you need it, such as corporate/territorial levels. Note the username, amd that you cannot specify a password. Complete all the mandatory fields (owner ID, system default, group, approvers, etc).
When you have made this user go to the API keys tab. Enter a description for your new set of keys, and save it. When you do this you'll see the public and private keys once (and once only). Note them down.
Authorisation Header
In Python:
>>> import base64
>>> base64.b64encode("a+b:c")
...where a is your ConnectWise company name (what you type in in the login box), b is your public key, and c is your private key. This will return something which will be what you use to access the system. Copy it.
Making your first request
Now in Python make a new file and put this in it (this is quick and dirty but it should get you started):
import requests
cwToken = ""
# This is the ConnectWise access code generated earlier
cwUrl = "https://api-eu.myconnectwise.net/v4_6_release/apis/3.0/"
# check the URL matches your region, look at your CW Manage login box if not
cwHeaders = {"Authorization":"Basic " + cwToken,
"clientID":"<insertyoursecretClientIDhere>",
"Content-Type":"application/json"}
# this is your authorisation payload
try:
r = requests.get(cwUrl + "company/companies?pageSize=1000&conditions=type/id==1", headers=cwHeaders)
# request has been made
r.raise_for_status()
except:
print(r.text)
raise
companies = r.json()
The companies object now contains a list of your first 1,000 clients (type is ID 1 -- client). I've included an example of the conditions string because it took me a while to work out what it is and how to use it. But just take it off if you don't want the server to do your filtering for you.
You'll then be able to modify the above, or turn it into a module (which is what I did) to then make quick and portable calls, something like
cw.getCompanies()
which would simply return you a JSON object with all your companies in.
Going further
Study the documentation!! It is comprehensive enough to get you started. And the forums are actively monitored by staff (although they help mostly with C# queries and not scripting).
Just an update for 2020 since Daniel's response was incredibly helpful, but is missing a change Connectwise made in 2019 that now requires ClientIDs in order to auth.
Make a client ID here (scroll to bottom, although it's quick and useful to read all of it):
https://developer.connectwise.com/ClientID#What_is_a_clientId.3F
Daniel's code should then look like:
cwHeaders = {"Authorization":"Basic " + cwToken,
"clientID":"<insertyoursecretClientIDhere>",
"Content-Type":"application/json"}

How to construct signing request for Amazon EC2 API call with filters?

This question is a follow-up to my earlier question on getting a REST API call to EC2 API working.
Having got that working, I wanted to generalize it and tried a couple of things. For example, I tried to filter by region name and make the request
https://ec2.amazonaws.com/?Action=DescribeRegions
&RegionName.1=us-east-1
&RegionName.2=eu-west-1
which they show in the documentation.
Signing that was easy, stick the RegionName(s) into the signing request in their alphabetical position and sign the whole thing just as I would without them. That worked out just fine.
So I progressed to the second example that they provide in the documentation.
https://ec2.amazonaws.com/?Action=DescribeRegions
&Filter.1.Name=endpoint
&Filter.1.Value.1=*ap*
OK, I tried to put the filters into my signing parameters in the alphabetically sorted location as required ...
char * signing_parameters_template =
"AWSAccessKeyId=%s&"
"Action=DescribeRegions&"
"Filter.1.Name=endpoint&"
"Filter.1.Value=*ap*&"
"SignatureMethod=HmacSHA256&"
"SignatureVersion=2&"
"Timestamp=%s&"
"Version=2013-08-15";
and sign that. I get an error that the signature doesn't match. I've tried a bunch of variations of this, no luck.
How does one sign a request that includes filters?
I have to escape the "*" in the filter
"Filter.1.Value=*ap*&"
That's it!

Cookie to log in with Jsoup?

For a project I'm trying to get data from a website only acessible when you're logged in from the site Goodreads.com. I'm new to Jsoup, since I'm using it only for this particular project. Getting the relevant data from the website is not a problem, but I can't seem to get to the particular page I need. The page I'm trying to acces is viewable only when logged in, when not logged in it rederects to the log-in page.
I've looked through the answers here, but the answers given so far have not helped.
What I have now:
String url = "http://www.goodreads.com/friend/user/7493379-judith";
Connection.Response res = Jsoup.connect("http://www.goodreads.com/user/sign_in")
.data("email", "MYEMAIL", "user_password", "MYPASSWORD")
.method(Connection.Method.POST)
.execute();
Document doc2 = res.parse();
String sessionId = res.cookie("_session_id");
Document doc = Jsoup.connect(url)
.cookie("_session_id", sessionId)
.get();
I got this far with help of the answers here, but it doesn't work, I'm still only getting the data from the log-in page it rederects to.
I have several questions:
Most importantly of course; How can I make it work?
The given answers here heve used method.(Method.POST) instead of method.(Connection.Method.POST) . When I use the first one however, I get an error that Method cannot be resolved. Anyone know why this is?
The examples I've seen have used "username" and "password" in .data() . What exactly do these refer to? I've now used the name of the input box. Is it the name, the type, the id, what exactly? Since Goodreads does not refer to the log in as the username, but as the e-mail, I assume I have to change them. (username & password doesn't work either)
Examples also use http://example.com/login.php as example url. Goodreads doesn't have a /login.php page though. Am I correct to assume I have to use the url with the log-in screen?
_session_id is the name of the relevant cookie on Goodreads.
I'd be very grateful if anyone can point me in the right direction!
See carefully what data is posted on login:
user[email]:email#email
remember_me:on
user[password]:plain_pasword
n:667387
So your post must execute exact same keys.
2.Make sure, you make right import: import org.jsoup.Connection.Method;
but Connection.Method.POST is still good.
3.See p1
4.Yes, you are correct
5.what is the question?
Goodreads requires two things when logging in: first, that you have a session ID stored in a cookie, and second, that you have a random generated number. You can get these when first visiting the login page without logging in: it will set a cookie with a session ID, and the form will contain a hidden input form (i.e. ) with the name "n" and value a number. Save these and pass them along as respectively a cookie and a form value when logging in.
Some remarks about the way I found this out:
The first thing you need to realise is that you're trying to recreate the exact same requests your browser does with Jsoup. So, in order to check whether what you have right now will work, you can try to recreate the exact same situation with your browser.
To recreate your code, I went to the login page, then I deleted all my Goodreads cookies (as you don't send along any cookies when you send the login request as well), and attempted to sign in with only passing the username and password form values. It gave an error that my session had timd out. When I first loaded the login page and then deleted all cookies except the session ID and did not remove the "n" form value, I could log in successfully. Therefore, you want to make a general GET request to the sign in page first, retrieve the session ID cookie you get there and the hidden form value, and pass it along with the POST request.
It could be that the API changed or that there just are several ways. Using Connection.Method.POST will do fine, in any case.
Yes, they refer to the names of the input boxes. This should be id, however, since name was used in the past and not all versions of all browsers supported passing the ids as data, most websites are just adding both. Either should be fine.
If you look at the source code of the sign in form, you can see that the "method" attribute of the form element is indeed the sign in page itself, so that's where it sends the request to.
PS. As a general tip, you can use the Firefox extension "Tamper Data" to remove form data or even cookies (though there are easier extensions for that).
You can log in with this code:
public static void main(String[] args) throws Exception {
Connection.Response execute = Jsoup
.connect("https://www.goodreads.com/")
.method(Connection.Method.GET).execute();
Element sign_in = execute.parse().getElementById("sign_in");
String authenticityToken = sign_in.select("input[name=authenticity_token]").first().val();
String n = sign_in.select("input[name=n]").first().val();
Document document = Jsoup.connect("https://www.goodreads.com/user/sign_in")
.data("cookieexists", "✓")
.data("authenticity_token", authenticityToken)
.data("user[email]", "user#email.com")
.data("user[password]", "password")
.data("remember_me", "on")
.data("n", n)
.cookies(execute.cookies())
.post();
}

retrieving 'pre windows 2000 logon' name from LDAPMessage object in win32api C++

I've been asked to look at windows service which retrieves data from an Active Directory tree using the win32 LDAP API and outputs JSON data to a text file. It works fine but I need to modify it so that the i get the 'pre windows 2000' login name. The service is written in c++.
The service already successfully retrieves various other attribute strings using:
PTSTR *pszValues=ldap_get_values(pLdap,pEntry,szAttribute);
and:
if (_tcscmp(szAttribute,TEXT("uUsnChanged"))==0) // uSNChanged is an example of an attribute
pItemInfo->uUsnChanged=_tcstoui64(pszValues[0],NULL,10); // pItemInfo is a struct defined elsewhere to hold the results for any given entry
i looked on http://msdn.microsoft.com/en-us/library/ms679021(v=VS.85).aspx to see if there is an attribute for 'pre windows 2000' login or something similar in the hope that I could just add this as another 'szAttribute' (to replace "uUsnChanged" in this example) and had no luck. Looking at the API i have been unable to come up with a way of getting this information.
i found the attribute 'sAMAccountName' which i thought would provide the information needed but it only gives me the name part of the DOMAIN/name format. Typical, it's the other part i want!
does anyone have any ideas on how to get the 'pre windows 2000' string from 'pEntry'?
#JPBlanc We are getting the correct nETBIOSName attribute now when running it on the test server. The app works on the assumption that there is a maximum of one nETBIOSName attribute per DC. It finds it by doing the following:
gets the default host using ldap_init(NULL,0)
get the 'configuration naming context' using ldap_search_s(pLdap,NULL,LDAP_SCOPE_BASE,NULL,pszAttrs,FALSE,&pResults); passing in the connection handle as the first parameter
retrieves the 'configurationNamingContext' attribute using ldap_get_values(pLdap,pEntry,TEXT("configurationNamingContext"));
concatenates "CN=Partitions," to the beggining of the string giving something like "CN=Partitions,CN=Configuration,DC=domain,DC=com,DC=au"
it then performs a search using ldap_search_s(pLdap,szPartitionNC,LDAP_SCOPE_SUBTREE,TEXT("(nETBIOSName=*)"),pszAttrs,FALSE,&pResults);
then it loops through the results looking for anything with a 'nETBIOSName' attribute and once it finds one it breaks out of the loop and returns the value.
Do you know if this is sufficient to work in any AD configuration?
Be careful, the Domain part of the 'pre windows 2000 domain' can be completly different from the user Principal Name (user#domain) use to logon onto Active-Directory. the DOMAIN is the Primary Domain Controleur name or the Netbios domain name. DOMAIN is created during domain creation, by default it's part of the DNS name, but it can be completly changed during domain creation.
You can find it with nETBIOSName attribute :
ldifde -f netbios.ldf -d "CN=Partitions,CN=Configuration,DC=your-DNS-Name" -r "(netbiosname=*)"
A best filter would be
(&(objectcategory=crossref)(dnsHostName=<DomainDNSName>)(netbiosname=*))
SAM-Account-Name Attribute (sAMAccountName)