User is null in the Google Cloud Api - google-app-engine

I followed the instructions in this tutorial.
https://developers.google.com/appengine/docs/java/endpoints/getstarted/auth
when i deployed my code. and went to test my app.
with the following url
http://chandru-compute.appspot.com/_ah/api/explorer
My
helloworld.greetings.multiply and
helloworld.greetings.getGreeting works as expected.
But i have issues with the helloworld.greetings.authed method.
The user object is always null.
Here is the code.
package com.google.devrel.samples.helloendpoints;
import com.google.api.server.spi.config.Api;
import com.google.api.server.spi.config.ApiMethod;
import com.google.appengine.api.users.User;
import com.google.appengine.api.users.UserService;
import com.google.appengine.api.users.UserServiceFactory;
import javax.inject.Named;
import java.util.ArrayList;
/**
* Defines v1 of a helloworld API, which provides simple "greeting" methods.
*/
#Api(
name = "helloworld",
version = "v1",
clientIds = {com.google.api.server.spi.Constant.API_EXPLORER_CLIENT_ID}
)
public class Greetings {
public static ArrayList<Greeting> greetings = new ArrayList<Greeting>();
static {
greetings.add(new Greeting("hello world!"));
greetings.add(new Greeting("goodbye world!"));
}
public Greeting getGreeting(#Named("id") Integer id) {
return greetings.get(id);
}
#ApiMethod(name = "greetings.multiply", httpMethod = "post")
public Greeting insertGreeting(#Named("times") Integer times, Greeting greeting) {
Greeting response = new Greeting();
StringBuilder responseBuilder = new StringBuilder();
for (int i = 0; i < times; i++) {
responseBuilder.append(greeting.getMessage());
}
response.setMessage(responseBuilder.toString());
return response;
}
#ApiMethod(name = "greetings.authed", path = "greeting/authed")
public Greeting authedGreeting(User user) {
//Greeting response = new Greeting("hello " + user.getEmail());
Greeting response;
if (user == null) {
UserService userService = UserServiceFactory.getUserService();
User user2 = userService.getCurrentUser();
String text = null;
if (user2 != null){
text = user2.getEmail();
}
response = new Greeting("hello world : Email2" + text );
} else {
response = new Greeting("hello world : Email " + user.getEmail() );
}
return response;
}
}

I had same problem, it helped for me to add
scopes = {"https://www.googleapis.com/auth/userinfo.email"}
into my Greetings #Api annotation. So the whole final #Apilook like
#Api(
name = "helloworld",
version = "v1",
clientIds = { com.google.api.server.spi.Constant.API_EXPLORER_CLIENT_ID },
scopes = {"https://www.googleapis.com/auth/userinfo.email"}
)
Then deploy, reload Api Explorer page and also turn on "Authorize requests using OAuth 2.0" option with same scope.

I am getting the same problem. And if you throw an OAuthRequestException Exception and test the service via the API Explorer console, you will get a message saying This method requires you to be authenticated. You may need to activate the toggle above to authorize your request using OAuth 2.0. When you try to enable the OAuth 2.0 toggle it requests in a new window to Select OAuth 2.0 scopes, and I have not been able to find which scopes are needed or figure out how I can test a cloud end-point service with authorization from the API Explorer console.

First of all, in the API explorer, you need to authenticate the request with OAuth using the Authorize requests using OAuth 2.0 toggle in the user interface.
If the user is still null check that among the client ids there is the ID for the API explorer
#Api(
name = "myAPIName",
version = "v1",
clientIds = { com.google.api.server.spi.Constant.API_EXPLORER_CLIENT_ID }
)
This is the only thing that is needed to obtain a not null User argument.

Related

Login after signup in identity server4

I am trying to login user as soon as he/she registers.
below is the scenario
1)Registration page is not on identity server.
2)Post user details to Id server from UI for user creation.
3)On successful user creation login the user and redirect.
4)Trying to do it on native app.
I tried it with javascript app but redirection fails with 405 options call.
(tried to redirect to /connect/authorize)
on mobile app, don't want user to login again after signup for UX.
Has anyone implemented such behavior
tried following benfoster
Okay so finally i was able to get it working with authorization code flow
Whenever user signs up generate and store a otp against the newly created user.
send this otp in post response.
use this otp in acr_value e.g acr_values=otp:{{otpvalue}} un:{{username}}
client then redirects to /connect/authorize with the above acr_values
below is the identity server code which handles the otp flow
public class SignupFlowResponseGenerator : AuthorizeInteractionResponseGenerator
{
public readonly IHttpContextAccessor _httpContextAccessor;
public SignupFlowResponseGenerator(ISystemClock clock,
ILogger<AuthorizeInteractionResponseGenerator> logger,
IConsentService consent,
IProfileService profile,
IHttpContextAccessor httpContextAccessor)
: base(clock, logger, consent, profile)
{
_httpContextAccessor = httpContextAccessor;
}
public override async Task<InteractionResponse> ProcessInteractionAsync(ValidatedAuthorizeRequest request, ConsentResponse consent = null)
{
var processOtpRequest = true;
var isAuthenticated = _httpContextAccessor.HttpContext.User.Identity.IsAuthenticated;
// if user is already authenticated then no need to process otp request.
if (isAuthenticated)
{
processOtpRequest = false;
}
// here we only process only the request which have otp
var acrValues = request.GetAcrValues().ToList();
if (acrValues == null || acrValues.Count == 0)
{
processOtpRequest = false;
}
var otac = acrValues.FirstOrDefault(x => x.Contains("otp:"));
var un = acrValues.FirstOrDefault(x => x.Contains("un:"));
if (otac == null || un == null)
{
processOtpRequest = false;
}
if (processOtpRequest)
{
var otp = otac.Split(':')[1];
var username = un.Split(':')[1];
// your logic to get and check opt against the user
// if valid then
if (otp == { { otp from db for user} })
{
// mark the otp as expired so that it cannot be used again.
var claimPrincipal = {{build your principal}};
request.Subject = claimPrincipal ;
await _httpContextAccessor.HttpContext.SignInAsync({{your auth scheme}}, claimPrincipal , null);
return new InteractionResponse
{
IsLogin = false, // as login is false it will not redirect to login page but will give the authorization code
IsConsent = false
};
}
}
return await base.ProcessInteractionAsync(request, consent);
}
}
dont forget to add the following code in startup
services.AddIdentityServer().AddAuthorizeInteractionResponseGenerator<SignupFlowResponseGenerator>()
You can do that by using IdentityServerTools class that IdentityServer4 provide to help issuing a JWT token For a Client OR a User (in your case)
So after the user signs up, you already have all claims needed for generating the token for the user:
including but not limited to: userid, clientid , roles, claims, auth_time, aud, scope.
You most probably need refresh token if you use hybrid flow which is the most suitable one for mobile apps.
In the following example, I am assuming you are using ASP.NET Identity for Users. The IdentityServer4 Code is still applicable regardless what you are using for users management.
public Constructor( UserManager<ApplicationUser> userManager,
SignInManager<ApplicationUser> signInManager,
IClientStore clientStore,
IdentityServerTools identityServerTools,
IRefreshTokenService refreshTokenService)
{// minimized for clarity}
public async Task GenerateToken(ApplicationUser user
)
{
var principal = await _signInManager.CreateUserPrincipalAsync(user);
var claims = new List<Claim>(principal.Claims);
var client = await clientStore.FindClientByIdAsync("client_Id");
// here you should add all additional claims like clientid , aud , scope, auth_time coming from client info
// add client id
claims.Add(new Claim("client_id", client.ClientId));
// add authtime
claims.Add(new Claim("auth_time", $"{(Int32)(DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1))).TotalSeconds}"));
// add audiences
var audiences = client.AllowedScopes.Where(s => s != "offline_access" && s != "openid" && s != "profile");
foreach (var audValue in audiences)
{
claims.Add(new Claim("aud", audValue));
}
// add /resources to aud so the client can get user profile info.
var IdentityServiceSettings = _configuration.GetSection("IdentityService").Get<IdentityServiceConsumeSettings>();
claims.Add(new Claim("aud", $"{IdentityServiceUrl}/resources"));
//scopes for the the what cook user
foreach (var scopeValue in client.AllowedScopes)
{
claims.Add(new Claim("scope", scopeValue));
}
//claims.Add(new Claim("scope", ""));
claims.Add(new Claim("idp", "local"));
var accesstoken = identityServerTools.IssueJwtAsync(100, claims);
var t = new Token
{
ClientId = "client_id",
Claims = claims
};
var refereshToken = refreshTokenService.CreateRefreshTokenAsync(principal, t, client);
}
This is just a code snippet that needs some changes according to your case

Authentication with custom API controller with Azure Mobile App and Xamarin

I have create a Mobile App service with Azure. I have created a new custom controller as seen below.
[MobileAppController]
public class NewsController : ApiController
{
public ApiServices Services { get; set; }
// GET api/News
public async Task<IEnumerable<NewsItem>> Get()
{//returns some data}
}
Within Azure I have enabled authentication and set the options to Active Directory as seen below.
I'm trying to consume the API within a Xamarin iOS application.
I create a access token via Active Directory as seen below and this works and generates the token correctly.
public static class ServicePrincipal
{
static string authority = "https://login.microsoftonline.com/xxx";
static string clientId = "xxx";
static string clientSecret = "xx";
static string resource = "xx";
public static async Task<AuthenticationResult> GetS2SAccessTokenForProdMSA()
{
return await GetS2SAccessToken();
}
static async Task<AuthenticationResult> GetS2SAccessToken()
{
try
{
AdalInitializer.Initialize();
var clientCredential = new ClientCredential(clientId, clientSecret);
var context = new AuthenticationContext(authority, false);
var authenticationResult = await context.AcquireTokenAsync(
resource,
clientCredential);
return authenticationResult;
}
catch (Exception ex)
{
throw;
}
}
}
However when trying to consume the API i always get an unauthorized exception.
I have tried authenticating by passing the token to the custom API like this. This throws an unauthorized exception
var client = new MobileServiceClient("THE URL");
var authenticationResult = await ServicePrincipal.GetS2SAccessTokenForProdMSA();
var authHeader = new Dictionary<string, string> { { "Bearer", authenticationResult.AccessToken } };
var orderResult = await client.InvokeApiAsync("News", HttpMethod.Get, authHeader);
I also tried the following, which doesn't work either.
CurrentPlatform.Init();
var client = new MobileServiceClient("THE URL");
var authenticationResult = await ServicePrincipal.GetS2SAccessTokenForProdMSA();
JObject payload = new JObject();
payload["access_token"] = authenticationResult.AccessToken;
await client.LoginAsync(MobileServiceAuthenticationProvider.WindowsAzureActiveDirectory, payload);
Can you see any issues here, how do i pass though the authorization token?
I suggest enabling application logging in the Azure portal and then looking to see what the authentication error is.

Error 404 when calling Google Cloud Endpoint API from Google Apps Script

I am trying to call a Google Cloud Endpoint API (developed on App Engine) via Google Apps Script. The endpoint is up and running, honestly I don't know which URL I should use but through Google Chrome Web Tools it looks like the URL is something like:
https://myapp.appspot.com/_ah/api/myendpointapi/v1/myEndPointMethod/
Along with API parameters directly included in the URL, separeted by slashes:
https://myapp.appspot.com/_ah/api/myendpointapi/v1/myEndPointMethod/param1value/param2value/...
Now, in order to call that API from Google App Script I am using the following code snippet:
function myFunction() {
var params =
{
"param1" : "param1value",
"param2" : "param2value",
};
var result = UrlFetchApp.fetch('https://myapp.appspot.com/_ah/api/myendpointapi/v1/myEndPointMethod/', params);
DocumentApp.getUi().alert(result);
}
However I always get a 404 error. If I have to be honest I don't even know if UrlFetchApp is the correct way of calling the API. I noticed this thread on StackOverflow but no one answered. What's the correct URL to use? Many thanks.
EDIT: Now I am trying with an API method which does not require any parameter. I found a way to call a specific URL (using method='get' as suggested by the answer below) but now I get a 401 error because it says I am not logged in. I believe I need to use some kind of OAuth parameter now. Any idea? I tryed using OAuthConfig but no luck with that as well :( From App Engine logs I can see the following error:
com.google.api.server.spi.auth.GoogleIdTokenUtils verifyToken: verifyToken: null
com.google.api.server.spi.auth.AppEngineAuthUtils getIdTokenEmail:
getCurrentUser: idToken=null
function myFunction() {
var result = UrlFetchApp.fetch('myurl', googleOAuth_());
result = result.getContentText();
}
function googleOAuth_() {
var SCOPE = 'https://www.googleapis.com/auth/drive';
var NAME = 'myAPIName';
var oAuthConfig = UrlFetchApp.addOAuthService(NAME);
oAuthConfig.setRequestTokenUrl('https://www.google.com/accounts/OAuthGetRequestToken?scope='+SCOPE);
oAuthConfig.setAuthorizationUrl('https://www.google.com/accounts/OAuthAuthorizeToken');
oAuthConfig.setAccessTokenUrl('https://www.google.com/accounts/OAuthGetAccessToken');
oAuthConfig.setConsumerKey('anonymous');
oAuthConfig.setConsumerSecret('anonymous');
return {oAuthServiceName:NAME, oAuthUseToken:'always'};
}
UrlFetchApp is the only way to call a Google Cloud Endpoints API at the moment. The second parameter to UrlFetchApp.fetch is a special key-value map of advanced options. To pass POST parameters, you need to do the following:
UrlFetchApp.fetch(url, {
method: 'post',
payload: {
"param1" : "param1value",
"param2" : "param2value",
}
});
I was fighting a similar (not the same) problem, when testing feasibility of a GCM backed by EndPoints server. Basically testing if it is possible to get the Google Spreadsheet Appscript to send notification to an Android device. Please bear with me, the following explanation may be a bit convoluted;
Starting with a standard 'Cloud Messaging for Android', backed by the 'App Engine Backend with Google Cloud Messaging', I managed to build a test system that would send messages between Android devices (Github here).
Here is a VERY sparse EndPoints server code that handles register / un-register Android devices, as well as reporting registered devices and sending a message to a list of registered devices.
WARNING: This is not a production quality code, it is stripped of any logging, error handling in order to keep it short.
#Api( name = "gcmEP", version = "v1",
namespace = #ApiNamespace(ownerDomain = "epgcm.example.com", ownerName = "epgcm.example.com", packagePath = "" )
)
public class GcmEP {
#ApiMethod(name = "registToken")
public void registToken(#Named("token") String token) {
if (ofy().load().type(TokenRec.class).filter("token", token).first().now() == null) {
ofy().save().entity(new TokenRec(token)).now();
}
}
#ApiMethod(name = "unregToken")
public void unregToken(#Named("token") String token) {
TokenRec record = ofy().load().type(TokenRec.class).filter("token", token).first().now();
if (record != null) {
ofy().delete().entity(record).now();
}
}
#ApiMethod(name = "listTokens")
public CollectionResponse<TokenRec> listTokens() {
return CollectionResponse.<TokenRec>builder().setItems(ofy().load().type(TokenRec.class).list()).build();
}
#ApiMethod(name = "sendMsg")
public void sendMsg(#Named("message") String message) throws IOException {
if (message != null && message.length() > 0) {
Sender sender = new Sender(System.getProperty("gcm.api.key"));
Message msg = new Message.Builder().addData("message", message).build();
for (TokenRec record : ofy().load().type(TokenRec.class).list()) {
Result result = sender.send(msg, record.getToken(), 4);
if (result.getMessageId() != null) {
// handle CanonicalRegistrationId
} else {
// handle errors, delete record
}
}
}
}
}
Android code for registration and message sending is shown here, even if it is not relevant.
GcmEP mRegSvc;
String mToken;
// register device on EndPoints backend server
private void registerMe() {
new Thread(new RegisterMe(this)).start();
}
private class RegisterMe implements Runnable {
Activity mAct;
public RegisterMe(Activity act) { mAct = act; }
public void run() {
String senderId = null;
if (mAct != null) try {
if (mRegSvc == null) {
mRegSvc = new GcmEP
.Builder(AndroidHttp.newCompatibleTransport(), new AndroidJsonFactory(), null).setRootUrl(UT.ROOT_URL).build();
}
senderId = getString(R.string.gcm_defaultSenderId);
mToken = InstanceID.getInstance(mAct).getToken(senderId, GoogleCloudMessaging.INSTANCE_ID_SCOPE, null);
mRegSvc.registToken(mToken).execute();
GcmPubSub.getInstance(mAct).subscribe(mToken, "/topics/global", null); // subscribing to all 'topics' from 'mToken'
} catch (IOException e) { e.printStackTrace(); }
}
}
// send message to EndPoints backend server
new Thread(new Runnable() {
#Override
public void run() {
if (mRegSvc != null) try {
mRegSvc.sendMsg("hello").execute();
} catch (IOException e) { e.printStackTrace(); }
}
}).start();
// receive GCM message
public class GcmListenSvc extends GcmListenerService {
#Override
public void onMessageReceived(String senderId, Bundle data) {
Log.i("_X_", data.getString("message"));
}
}
What is relevant, thought, there is also an APIs Explorer created for the project, that can be used to send messages to your Android device from any browser.
If you use this Explorer, you can see the GET, POST requests for your EndPoints backend server, i.e.
list all registered devices:
GET https://epgcm.appspot.com/_ah/api/gcmEP/v1/tokenrec?fields=items
send a message to all registered devices:
POST https://epgcm.appspot.com/_ah/api/gcmEP/v1/sendMsg/Hello%20World!
Now, you can use this knowledge to send messages to your Android device from an AppScript code as shown:
Version 1: Get list of registered devices and send a GCM message to all of them (or a filtered set).
function sendMsg() {
var msg = 'test from CODE.GS';
var url = 'https://epgcm.appspot.com/_ah/api/gcmEP/v1/tokenrec?fields=items';
var params = { method : 'get'};
var response = UrlFetchApp.fetch(url, params);
var data = JSON.parse(response.getContentText());
var regIds = [];
for (i in data.items)
regIds.push(data.items[i].token);
var payload = JSON.stringify({
'registration_ids' : regIds,
'data' : { 'message' : msg }
});
var params = {
'contentType' : 'application/json',
'headers' : {'Authorization' : 'key=AIza............................'},
'method' : 'post',
'payload' : payload
};
url = 'https://android.googleapis.com/gcm/send';
UrlFetchApp.fetch(url, params);
}
This version relies on code from an old YouTube video, and I don't know if the call to 'android.googleapis.com' is still supported (but it works).
Version 2: Use the EndPoints's 'sendMsg' directly.
function sendMsg() {
var msg = 'test from CODE.GS';
var params = { method : 'post'};
var url = 'https://demoepgcm.appspot.com/_ah/api/gcmEP/v1/sendMsg/' + encodeURIComponent(msg.trim());
UrlFetchApp.fetch(url, params);
}
I have to admit I've never written a line of JavaScript code before, so it may not be up-to-par, but I made it work as a 'proof of concept'.
I would like to get feedback about this problem from people-who-know, since there is so little published info on this specific issue.

WebApi2 Owin Claims Application Cookie

I have an SPA app built with AngularJS, the backend is WebApi2. I´m struggling with Authentication and Authorization. What I want in the long run is to enable authentication against Active Directory. But for now, I just trying to enable authorization for my APiControllers and setting a Cookie with Owin.
Here is my Owin Identity Helper class, I´m only adding 1 claim that is the serialized user info:
public void SignIn(bool rememberMe, T user)
{
var claims = new List<Claim>
{
new Claim(ClaimTypes.UserData, JsonConvert.SerializeObject(user)),
};
var claimsIdentity = new ClaimsIdentity(claims, DefaultAuthenticationTypes.ApplicationCookie);
AuthenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = rememberMe }, claimsIdentity);
}
Here is authentication in controller:
[HttpGet, HttpPost]
[AllowAnonymous]
[Route("authenticate")]
public HttpResponseMessage Authenticate()
{
var authenticated = IdentityContext.Current.IsAuthenticated;
if (!authenticated)
{
var user = new User();
user.Email = "roger#moore.com";
user.Name = "Roger Moore";
user.Id = 23;
IdentityContext.Current.SignIn(true, user);
return new HttpResponseMessage()
{
Content = new StringContent(
JsonConvert.SerializeObject(user),
Encoding.UTF8,
"application/json"
)
};
}
else
{
//return the user if authenticated
return new HttpResponseMessage()
{
Content = new StringContent(
JsonConvert.SerializeObject(IdentityContext.Current.User), //from claim
Encoding.UTF8,
"application/json"
)
};
}
}
My StartUp class
public partial class Startup
{
// For more information on configuring authentication, please visit http://go.microsoft.com/fwlink/?LinkId=301864
public void ConfigureAuth(IAppBuilder app)
{
// Enable the application to use a cookie to store information for the signed in user
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/account/signedout")
});
}
}
When I call the authenticate user I´m setting signing in, but when calling a controller with [Authorize] attribute, im not signed in. Furthermore, when having fiddler running I get the error:
"[Fiddler] Response Header parsing failed. This can be caused by an illegal HTTP response earlier on this reused server socket-- for instance, a HTTP/304 response which illegally contains a body. Response Data:"
Does anyone have any suggestions, or alternatives with example code for using JWT Token Authentication and Authorization From Angular to WebApi2?

Accessing oauth protected resource on Google App Engine

I'm trying to access an OAuth-protected resource on Google App Engine using a Java/Groovy client. However the authentication is not working and my GET requests are just bringing back the Google Accounts login page HTML.
I get the same results with HTTPBuilder/signpost and with google-oauth-java-client.
Here's what I've done:
Set up an OAuth provider as described in http://ikaisays.com/2011/05/26/setting-up-an-oauth-provider-on-google-app-engine/
Created a 'hello world' servlet (actually a Gaelyk groovlet) mapped to http://<my-app>.appspot.com/rest/hello
Deployed the servlet to gae and confirmed I can GET via a browser.
Added a security constraint to my web.xml and redeployed.
<security-constraint>
<web-resource-collection>
<web-resource-name>Rest</web-resource-name>
<url-pattern>/rest/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>*</role-name>
</auth-constraint>
</security-constraint>
Confirmed that a browser GET requires a Google Accounts login and that after login I can access the servlet.
Did the 3-legged OAuth dance as described in http://groovy.codehaus.org/modules/http-builder/doc/auth.html to get the access and client secret tokens.
Use the tokens in a RESTClient as follows (following instructions in the link above)
def client = new RESTClient('http://<my-app>.appspot.com' )
def consumerKey = <my consumer key>
def consumerSecret = <my consumer secret>
def accessToken = <my access token>
def secretToken = <my secret token>
client.auth.oauth consumerKey, consumerSecret, accessToken, secretToken
def resp = client.get(path:'/rest/hello')
assert resp.data == 'Hello world'
The assert fails since the response is the Google Accounts login page.
I get the same behaviour when using google-oauth-java-client.
I've been through the process above several times, checking for copy/paste errors in the tokens and ensuring that I'm not getting the tokens mixed up.
This is with Groovy 1.8.2, OSX Java 1.6.0_29, HTTPBuilder 0.5.1, gaelyk 1.1.
Any ideas? Thanks.
OK, no response on this so here's how I worked around it.
I gave up on using oauth... google only claim 'experimental' status for this anyway so maybe it fundamentally doesn't work yet.
However I get good results using the ClientLogin protocol from my test client (equivalent to doing a manual login to Google Accounts like the one you do when accessing gmail)
I based this on the extremely useful article http://www.geekyblogger.com/2011/05/using-clientlogin-to-do-authentication.html. I had to extend in a few ways, code below:
import java.io.File;
import java.io.InputStream;
import java.io.LineNumberReader;
import java.io.StringReader;
import java.nio.charset.Charset;
import org.apache.commons.io.IOUtils;
import org.apache.http.Header;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.mime.MultipartEntity;
import org.apache.http.entity.mime.content.StringBody;
import org.apache.http.impl.client.DefaultHttpClient;
import com.google.appengine.repackaged.com.google.common.io.Files;
import com.google.cloud.sql.jdbc.internal.Charsets;
public class Login {
public static void main(String[] args) throws Exception {
// This file contains my
// google password. Note that this has to be an app-specific
// password if you use 2-step verification
File passFile = new File("/Users/me/pass.txt");
String pass = Files.toString(passFile, Charsets.UTF_8);
String authCookie = loginToGoogle("myemail#gmail.com", pass,
"http://myapp.appspot.com");
DefaultHttpClient client = new DefaultHttpClient();
// A te
HttpGet get = new HttpGet("http://myapp.appspot.com/rest/blah");
get.setHeader("Cookie", authCookie);
HttpResponse response = client.execute(get);
response.getEntity().writeTo(System.out);
}
public static String loginToGoogle(String userid, String password,
String appUrl) throws Exception {
HttpClient client = new DefaultHttpClient();
HttpPost post = new HttpPost(
"https://www.google.com/accounts/ClientLogin");
MultipartEntity reqEntity = new MultipartEntity();
reqEntity.addPart("accountType", new StringBody("HOSTED_OR_GOOGLE",
"text/plain", Charset.forName("UTF-8")));
reqEntity.addPart("Email", new StringBody(userid));
reqEntity.addPart("Passwd", new StringBody(password));
reqEntity.addPart("service", new StringBody("ah"));
reqEntity.addPart("source", new StringBody(
"YourCompany-YourApp-YourVersion"));
post.setEntity(reqEntity);
HttpResponse response = client.execute(post);
if (response.getStatusLine().getStatusCode() == 200) {
InputStream input = response.getEntity().getContent();
String result = IOUtils.toString(input);
String authToken = getAuthToken(result);
post = new HttpPost(appUrl + "/_ah/login?auth=" + authToken);
response = client.execute(post);
Header[] cookies = response.getHeaders("SET-COOKIE");
for (Header cookie : cookies) {
if (cookie.getValue().startsWith("ACSID=")) {
return cookie.getValue();
}
}
throw new Exception("ACSID cookie cannot be found");
} else
throw new Exception("Error obtaining ACSID");
}
private static String getAuthToken(String responseText) throws Exception {
LineNumberReader reader = new LineNumberReader(new StringReader(
responseText));
String line = reader.readLine();
while (line != null) {
line = line.trim();
if (line.startsWith("Auth=")) {
return line.substring(5);
}
line = reader.readLine();
}
throw new Exception("Could not find Auth token");
}
}

Resources