Is it possible to get around the Cross-Origin limitation when calling the Google Places API Web service? - google-places-api

Is it possible enable the Google Placess API WebService to allow cross-origin requests from my domain so that I can access the service directly from the browser? I'v been experimenting with the API-keys by creating a Browser API key and then adding my domain to the referers list, but to no avail. Not sure if that is what the refeferer property is for anyway.
Is this limitation by design, or am I missing something here?
Google Places API WebService is the service that I want to use. Neither the Places Autocomplete or Places Search in the Places Library are suitable for my particular requirement.
Cheers
Stian

This is a client-side based limitation, so the short answer is: no.
However there are websites and services that try to surmount this problem by using scripts (loading them on the fly).
Have a look here and here (these articles are about generic cross-domain AJAX requests)

The Places-API is also available inside the Maps-Javascript-API, you don't need to struggle with cross-origins there.

Let me say its impossible to get around .I tried using java instead the code just works for http request(i used here is for graph.facebook.com):
public class search {
private static String readAll(Reader rd) throws IOException {
StringBuilder sb = new StringBuilder();
int cp;
while ((cp = rd.read()) != -1) {
sb.append((char) cp);
}
return sb.toString();
}
public static JSONObject readJsonFromUrl(String url) throws IOException, JSONException {
InputStream is = new URL(url).openStream();
try {
BufferedReader rd = new BufferedReader(new InputStreamReader(is, Charset.forName("UTF-8")));
String jsonText = readAll(rd);
JSONObject json = new JSONObject(jsonText);
return json;
} finally {
is.close();
}
}
public static void main(String[] args) throws Exception{
// TODO Auto-generated method stub
System.getProperties().put("http.proxyHost", "172.16.0.2");
System.getProperties().put("http.proxyPort", "8080");
JSONObject json = readJsonFromUrl("http://maps.googleapis.com/maps/api/place/nearbysearch/json?key=AIzaSyBRlMLIdoTk-j4OZCucR47rVMLhMmvZVRw&type=hospital&location=12.8213125%2C80.0442&radius=500&_=1427359809583");
System.out.println(json.toString());
// System.out.println(json.get("about"));
// System.out.println("hello ");
}
}
If you replace the link with places api web search it will not work,the reason is that google does not give its services on HTTP domain,,, and my code only works on HTTP domain(not HTTPS)

Related

How to serve sitemap.xml from outside project folder in Spring Boot 2

I have a Spring Boot 2 Web application which is a blogging website, where I have a dynamic sitemap.xml file. The sitemap.xml gets updated whenever we add a new article in the repository. Now I need to serve the sitemap.xml file from outside of the project location. Consider the sitemap.xml is present in the following location:
/home/admin/sitemap.xml
My requirement is, whenever a user hit the url https://<my_url>/sitemap.xml then the file should be served from the mentioned location. I have added the mapping for the same.
#Configuration
#AutoConfigureAfter(DispatcherServletAutoConfiguration.class)
public class WebConfiguration implements WebMvcConfigurer {
#Override
public void addResourceHandlers(final ResourceHandlerRegistry registry) {
registry.addResourceHandler("/sitemap.xml/**").addResourceLocations("/home/admin/sitemap.xml");
}
}
But the code is not working. Can anyone suggest that, what I am doing wrong here.
Finally, I have solved this by writing a GetMapping. Many solutions on the internet are saying that to return the sitemap.xml file as a String. But please note Google will not read that sitemap.xml file for the wrong Content-Type header. The Content-Type must be "application/xml". Following is my #GetMapping
#GetMapping(value = "/sitemap.xml")
public void serveSiteMapFile(HttpServletResponse response) throws IOException {
response.setContentType("application/xml");
try (BufferedReader bufferedReader =
new BufferedReader(new FileReader(new File("/home/admin/sitemap.xml")))) {
String line;
StringBuilder siteMapBuilder = new StringBuilder();
while ((line = bufferedReader.readLine()) != null) {
siteMapBuilder.append(line);
}
ServletOutputStream outStream = response.getOutputStream();
outStream.println(siteMapBuilder.toString());
outStream.flush();
outStream.close();
}
}

Server side authorization with Google Play Developer API?

Authorization is required to fetch information from the Google Play Developer API.
I know how to do this with Postman, but implementing authorization is much more cumbersome (redirect url, handling redirects, and so on...)
These would be the steps when you already have setup the auth data inside the Google Developer API Console.
1.) GET https://accounts.google.com/o/oauth2/auth?scope=https://www.googleapis.com/auth/androidpublisher&response_type=code&access_type=offline&redirect_uri=http://www.myurl.com/oauth2callback&client_id=1234567890.apps.googleusercontent.com
2.) get code which was sent to redirect url.
3.) POST https://accounts.google.com/o/oauth2/token
with
grant_type:authorization_code
code:[the code I got before]
client_id:1234567890.apps.googleusercontent.com
client_secret:[my client secret]
4.) Invoke GET https://www.googleapis.com/androidpublisher/v2/applications/packageName/purchases/subscriptions/subscriptionId/tokens/token
with:
Scope: https://www.googleapis.com/auth/androidpublisher
and:
access_token as query parameter I got before.
Now I want to do all this programmatically. Obviously not so easy. I thought the Google API Client Libraries will help, but I don't see, how these lib can help me with my use case.
For example classes like GoogleAuthorizationCodeFlow expect a user id at the moment of the request, but I not necessarily have one at this moment, so I wonder how this API should be used in a clean way.
Is there a clean way to handle OAuth2.0 easier / programmatically with some API to access Google Play Developer API? Otherwise I must implement it manually.
After lots of headache (like always with Google APIs and services) I figured out how one can access Google Play Developer API information (like billing) by using existing APIs.
1.) Create in Developer API Console a service account (JSON) key:
2.) Download this service-account-private-key.json file (don't mistake it with the OAuth2.0 client secret file!).
3.) In Google Play Developer Console go to Settings -> Users & Permissions -> Invite New User and set as user e-mail of the new user the client_email from the downloaded file. Assign the access rights you want to give to this users via the checkboxes inside this view (for example 'View financial data').
4.) Add the proper dependency to your project (version ...-1.23.0 does not work for me):
<dependency>
<groupId>com.google.apis</groupId>
<artifactId>google-api-services-androidpublisher</artifactId>
<version>v2-rev50-1.22.0</version>
</dependency>
5.) Load the service-account-private-key.json file into your application. In my case it's a webserver:
#Singleton
#Startup
public class WebserverConfiguration
{
private String serviceAccountPrivateKeyFilePath;
/** Global instance of the HTTP transport. */
public static HttpTransport HTTP_TRANSPORT;
/** Global instance of the JSON factory. */
public static JsonFactory JSON_FACTORY;
private GoogleCredential credential;
#PostConstruct
public void init()
{
assignServiceAccountFileProperty();
initGoogleCredentials();
}
public String getServiceAccountPrivateKeyFilePath()
{
return serviceAccountPrivateKeyFilePath;
}
public GoogleCredential getCredential()
{
return credential;
}
private void initGoogleCredentials()
{
try
{
newTrustedTransport();
newJsonFactory();
String serviceAccountContent = new String(Files.readAllBytes(Paths.get(getServiceAccountPrivateKeyFilePath())));
InputStream inputStream = new ByteArrayInputStream(serviceAccountContent.getBytes());
credential = GoogleCredential.fromStream(inputStream).createScoped(Collections.singleton(AndroidPublisherScopes.ANDROIDPUBLISHER));
}
catch (IOException | GeneralSecurityException e)
{
throw new InitializationException(e);
}
}
private void newJsonFactory()
{
JSON_FACTORY = JacksonFactory.getDefaultInstance();
}
private void assignServiceAccountFileProperty()
{
serviceAccountPrivateKeyFilePath = System.getProperty("service.account.file.path");
if (serviceAccountPrivateKeyFilePath == null)
{
throw new IllegalArgumentException("service.account.file.path UNKNOWN - configure it as VM startup parameter in Wildfly");
}
}
private static void newTrustedTransport() throws GeneralSecurityException, IOException
{
if (HTTP_TRANSPORT == null)
{
HTTP_TRANSPORT = GoogleNetHttpTransport.newTrustedTransport();
}
}
}
6.) Now I am able the fetch Google Play Developer API information, e.g. reviews:
private void invokeGoogleApi() throws IOException
{
AndroidPublisher publisher = new AndroidPublisher.Builder(WebserverConfiguration.HTTP_TRANSPORT, WebserverConfiguration.JSON_FACTORY, configuration.getCredential()).setApplicationName("The name of my app on Google Play").build();
AndroidPublisher.Reviews reviews = publisher.reviews();
ReviewsListResponse reviewsListResponse = reviews.list("the.packagename.of.my.app").execute();
logger.info("review list response = " + reviewsListResponse.toPrettyString());
}
This worked.
I cannot test it yet, but I'm sure that fetching the billing information works as well:
private SubscriptionPurchase getPurchase() throws IOException
{
AndroidPublisher publisher = new AndroidPublisher.Builder(WebserverConfiguration.HTTP_TRANSPORT, WebserverConfiguration.JSON_FACTORY, configuration.getCredential()).setApplicationName("The name of my app on Google Play").build();
AndroidPublisher.Purchases purchases = publisher.purchases();
SubscriptionPurchase purchase = purchases.subscriptions().get("the.packagename.of.my.app", "subscriptionId", "billing token sent by the app").execute();
//do something or return
return purchase;
}
There are complete code samples and documentation for doing this in Java here
In the Java source code this authorizes like this
private static Credential authorizeWithServiceAccount(String serviceAccountEmail)
throws GeneralSecurityException, IOException {
log.info(String.format("Authorizing using Service Account: %s", serviceAccountEmail));
// Build service account credential.
GoogleCredential credential = new GoogleCredential.Builder()
.setTransport(HTTP_TRANSPORT)
.setJsonFactory(JSON_FACTORY)
.setServiceAccountId(serviceAccountEmail)
.setServiceAccountScopes(
Collections.singleton(AndroidPublisherScopes.ANDROIDPUBLISHER))
.setServiceAccountPrivateKeyFromP12File(new File(SRC_RESOURCES_KEY_P12))
.build();
return credential;
}

Implemented Spring OAuth2, getting same access token from different devices

Implemented Spring OAuth2 security and getting same access token when logging with the same user but from different device. When i logout from any one of these devices(revoke Token)other devices are also getting logged out. Is it a expected behavior or i am missing something ? hoping that sharing the massive code will not help much so kept the question short and simple.
The default behaviour of the DefaultTokenServices is to re-use existing tokens (based on the behaviour of the existing TokenStore implementations)
http://forum.spring.io/forum/spring-projects/security/oauth/121797-multiple-valid-oauth-access-tokens-for-same-client
If you want every device to be given different access_token then create your own AuthenticationKeyGenerator e.g. send your device id on authorization process and let your AuthenticationKeyGenerator process that device id to create access_token specific for that device.
(Please read org.springframework.security.oauth2.provider.token.DefaultAuthenticationKeyGenerator code to put the following solution into context)
DefaultAuthenticationKeyGenerator is available in spring. I just created a custom version with the same code with one extension, i.e., device_id sent from the client as a request parameter is retrieved from OAuth2Authentication as follows;
String deviceId = authentication.getOAuth2Request().getRequestParameters().get("device_id")
and then is put into the values map (used to generate the token finally). Hence the device_id becomes a part of the token resulting in a unique token per device.
Following is the full solution which is mostly the DefaultAuthenticationKeyGenerator apart from the bit explained above.
public class CustomAuthenticationKeyGenerator implements AuthenticationKeyGenerator
{
private static final String CLIENT_ID = "client_id";
private static final String SCOPE = "scope";
private static final String USERNAME = "username";
#Override
public String extractKey(OAuth2Authentication authentication) {
Map<String, String> values = new LinkedHashMap<String, String>();
OAuth2Request authorizationRequest = authentication.getOAuth2Request();
if (!authentication.isClientOnly()) {
values.put(USERNAME, authentication.getName());
}
values.put(CLIENT_ID, authorizationRequest.getClientId());
if (authorizationRequest.getScope() != null) {
values.put(SCOPE, OAuth2Utils.formatParameterList(authorizationRequest.getScope()));
}
String deviceId = authorizationRequest.getRequestParameters().get(CustomHeader.device_id.name());
if(deviceId != null && !deviceId.isEmpty()) {
values.put("device_id", deviceId);
}
MessageDigest digest;
try {
digest = MessageDigest.getInstance("MD5");
}
catch (NoSuchAlgorithmException e) {
throw new IllegalStateException("MD5 algorithm not available. Fatal (should be in the JDK).");
}
try {
byte[] bytes = digest.digest(values.toString().getBytes("UTF-8"));
return String.format("%032x", new BigInteger(1, bytes));
}
catch (UnsupportedEncodingException e) {
throw new IllegalStateException("UTF-8 encoding not available. Fatal (should be in the JDK).");
}
}
}
For those who are facing the same issue can work on the replied solution by MangEngkus, for precise solution you can also refer this link Spring OAuth2 Generate Access Token per request to the Token Endpoint

Receiving files form PLUpload in WICKET

Im trying to integrate PLUpload into my wicket application. First steps are looking clear. Im able to choose files and when i click the "upload"-button i receive an request on server-side in my PLUploadBehavior based on AbstractDefaultAjaxBehavior. But it does not seems to be a MultiPart request.
public abstract class PLUploadBehavior extends AbstractDefaultAjaxBehavior {
public PLUploadBehavior() {
}
#Override
public void renderHead(final Component component, IHeaderResponse response) {
super.renderHead(component, response);
response.render(JavaScriptHeaderItem.forReference(new JavaScriptResourceReference(PLUploadBehavior.class, "plupload.full.min.js"));
StringBuffer script = new StringBuffer();
//build the init-script...
response.render(OnLoadHeaderItem.forScript(script.toString()));
}
#Override
protected void respond(AjaxRequestTarget target) {
Request request = getComponent().getRequest();
//received request here, but don't know hot to access files
if (request instanceof IMultipartWebRequest) {
System.out.println("Multipart!!!");
}
}
}
I followed the tutorial for plupload and have no form in my html template. There is none in the tutorial, so i think i don't need it. Anyone an idea to access the files on server-side?
After some more coffee i found the solution to my problem. The example on wicket in action can get adapted to the use with an Behavior. Thanks to Martin Grigorov and the great Wicket Team!

ASP.NET Web API session or something?

I need to store some information in session(or in whatever in ASP.NET Web API) that I need to retrieve in every API request. We will have one api IIS web site and multiple web site binding will be added through host header. When any request comes in for example, api.xyz.com, host header will be checked and store that website information in session that will be used in each subsequent api request when making a call to database.
I know there is no support for session in ASP.NET Web API. Is there any other way to handle this kind of situation? Where can I store information that can be retrieving in each subsequent request?
thanks.
in Global.asax add
public override void Init()
{
this.PostAuthenticateRequest += MvcApplication_PostAuthenticateRequest;
base.Init();
}
void MvcApplication_PostAuthenticateRequest(object sender, EventArgs e)
{
System.Web.HttpContext.Current.SetSessionStateBehavior(
SessionStateBehavior.Required);
}
give it a shot ;)
Well, REST by design is stateless. By adding session (or anything else of that kind) you are making it stateful and defeating any purpose of having a RESTful API.
The whole idea of RESTful service is that every resource is uniquely addressable using a universal syntax for use in hypermedia links and each HTTP request should carry enough information by itself for its recipient to process it to be in complete harmony with the stateless nature of HTTP".
So whatever you are trying to do with Web API here, should most likely be re-architectured if you wish to have a RESTful API.
With that said, if you are still willing to go down that route, there is a hacky way of adding session to Web API, and it's been posted by Imran here http://forums.asp.net/t/1780385.aspx/1
Code (though I wouldn't really recommend that):
public class MyHttpControllerHandler
: HttpControllerHandler, IRequiresSessionState
{
public MyHttpControllerHandler(RouteData routeData): base(routeData)
{ }
}
public class MyHttpControllerRouteHandler : HttpControllerRouteHandler
{
protected override IHttpHandler GetHttpHandler(RequestContext requestContext)
{
return new MyHttpControllerHandler(requestContext.RouteData);
}
}
public class ValuesController : ApiController
{
public string GET(string input)
{
var session = HttpContext.Current.Session;
if (session != null)
{
if (session["Time"] == null)
{
session["Time"] = DateTime.Now;
}
return "Session Time: " + session["Time"] + input;
}
return "Session is not availabe" + input;
}
}
and then add the HttpControllerHandler to your API route:
route.RouteHandler = new MyHttpControllerRouteHandler();
In WebApi 2 you can add this to global.asax
protected void Application_PostAuthorizeRequest()
{
System.Web.HttpContext.Current.SetSessionStateBehavior(System.Web.SessionState.SessionStateBehavior.Required);
}
Then you could access the session through:
HttpContext.Current.Session
You can use cookies if the data is small enough and does not present a security concern. The same HttpContext.Current based approach should work.
Request and response HTTP headers can also be used to pass information between service calls.
Now in 2017 with ASP.Net Core you can do it as explained here.
The Microsoft.AspNetCore.Session package provides middleware for managing session state.
Startup.cs
public void ConfigureServices(IServiceCollection services)
{
// Adds a default in-memory implementation of IDistributedCache.
services.AddDistributedMemoryCache();
services.AddSession(options =>
{
// Set a short timeout for easy testing.
options.IdleTimeout = TimeSpan.FromSeconds(10);
options.Cookie.HttpOnly = true;
});
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseSession();
}
From the Docs:
Introduction to session and application state in ASP.NET Core
Already tested on a working project

Resources