Bonita Web API - 401 Unauthorized Error - java

I am trying to use Bonita Web API. I My code is below. As you can see I call the loginservice before calling any other API service. It logs in OK 200. But when I make the subsequent call to get the list of processes I get a 401 error. You get a JSESSIONID from the first call and you are suppose to pass it to the subsequent calls to authenticate you.
var baseAddress = new Uri(<base address>);
var cookieContainer = new CookieContainer();
using (var handler = new HttpClientHandler() { CookieContainer = cookieContainer })
using (var client = new HttpClient(handler) { BaseAddress = baseAddress })
{
HttpResponseMessage result = client.PostAsync("/bonita/loginservice", new StringContent("login=<username>,password=<password>,redirect=false")).Result;
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage result2 = client.GetAsync("/bonita/API/bpm/process").Result;
result2.EnsureSuccessStatusCode();
}

This works for .Net 2.0 C# but has some interesting things to check.
WebClient wc = new WebClient();
wc.Proxy = WebRequest.GetSystemWebProxy();
//wc.Headers[HttpRequestHeader.AcceptEncoding] = "gzip, deflate";
string strLogin = wc.DownloadString("http://localhost:8080/bonita/loginservice?username=walter.bates&password=bpm&redirect=false");
wc.Headers[HttpRequestHeader.Cookie] = wc.ResponseHeaders[HttpResponseHeader.SetCookie].ToString();
string strCookie = wc.ResponseHeaders[HttpResponseHeader.SetCookie].ToString();
string strProcesses = wc.DownloadString("http://localhost:8080/bonita/API/bpm/process?p=0");
First of all you should know how to determine that the executed operation is successful ( login, getProcesses and whatever) When you try to login you will always get the header (for example "JSESSIONID=50E509D37AC28E2D725CBD45A8112FA7; Path=/bonita; HttpOnly") and OK 200 even if your login attempt in Bonita is unsuccesful.
For the successful login on the previous example
1) You must Pass mandatory form data: username, password and redirect You must also be sure to pass redirect in lower case ."False" will not work, "false" will work. So for .Net suppose you have a property-> Boolean redirect. You must make it lowercase with redirect.ToString().ToLower() cause either way the value will be "False" and you don't want that.
Let's say you try to login only with username and password without passing redirect. the result is that you will get both OK 200 and the header but you will also get a response which is wrong (the response must be empty), so on the next request (i.e getProcesses) you'll get (401) Unauthorized. Guess the results you will have if you pass redirect=False instead of redirect=false. Exactly the same.
2)You must get: strLogin="" // the body of the response must be empty strCookie="JSESSIONID=4F67F134840A2C72DBB968D53772FB22; Path=/bonita; HttpOnly"
For the successful getProcesses on the previous example you pass the header you got from login
wc.Headers[HttpRequestHeader.Cookie] = wc.ResponseHeaders[HttpResponseHeader.SetCookie].ToString();
and then you call the process and get a string in json format for example
"[{\"id\":\"6996906669894804403\",\"icon\":\"\",\"displayDescription\":\"\",\"deploymentDate\":\"2014-11-19 17:57:40.893\",\"description\":\"\",\"activationState\":\"ENABLED\",\"name\":\"Travel request\",\"deployedBy\":\"22\",\"displayName\":\"Travel request\",\"actorinitiatorid\":\"4\",\"last_update_date\":\"2014-11-19 17:57:41.753\",\"configurationState\":\"RESOLVED\",\"version\":\"1.0\"}]"
(or [] which means an empty json)
If the cookie is not passed correctly you will get again 401 error.
Solution for .Net 4.5.1
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
using System.Web;
namespace BonitaRestApi
{
class BonitaApi
{
private CookieCollection collection;
string strCookietoPass;
string sessionID;
static void Main(string[] args)
{
BonitaApi obj = new BonitaApi();
Task login = new Task(obj.Login);
login.Start();
login.Wait();
Console.ReadLine();
Task GetProcesses = new Task(obj.GetProcesses);
GetProcesses.Start();
GetProcesses.Wait();
Console.ReadLine();
Task logout = new Task(obj.Logout);
logout.Start();
logout.Wait();
Console.ReadLine();
}
public async void Login()
{
const string url = "http://localhost:8080/bonita/";
var cookies = new CookieContainer();
var handler = new HttpClientHandler();
handler.CookieContainer = cookies;
using (var client = new HttpClient(handler))
{
var uri = new Uri(url);
client.BaseAddress = uri;
//client.DefaultRequestHeaders.Accept.Clear();
//client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var content = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("username", "helen.kelly"),
new KeyValuePair<string, string>("password", "bpm"),
new KeyValuePair<string, string>("redirect", "false"),
new KeyValuePair<string, string>("redirectUrl", ""),
});
HttpResponseMessage response = await client.PostAsync("loginservice", content);
if (response.IsSuccessStatusCode)
{
var responseBodyAsText = await response.Content.ReadAsStringAsync();
if (!String.IsNullOrEmpty(responseBodyAsText))
{
Console.WriteLine("Unsuccessful Login.Bonita bundle may not have been started, or the URL is invalid.");
return;
}
collection= cookies.GetCookies(uri);
strCookietoPass = response.Headers.GetValues("Set-Cookie").FirstOrDefault();
sessionID = collection["JSESSIONID"].ToString();
Console.WriteLine(string.Format("Successful Login Retrieved session ID {0}", sessionID));
// Do useful work
}
else
{
Console.WriteLine("Login Error" + (int)response.StatusCode + "," + response.ReasonPhrase);
}
}
}
public async void Logout()
{
const string url = "http://localhost:8080/bonita/";
var cookies = new CookieContainer();
var handler = new HttpClientHandler();
handler.CookieContainer = cookies;
using (var client = new HttpClient(handler))
{
var uri = new Uri(url);
client.BaseAddress = uri;
var content = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("redirect", "false")
});
HttpResponseMessage response = await client.PostAsync("logoutservice", content);
if (response.IsSuccessStatusCode)
{
var responseBodyText = await response.Content.ReadAsStringAsync();
if (!String.IsNullOrEmpty(responseBodyText))
{
Console.WriteLine("Unsuccessful Logout.Bonita bundle may not have been started, or the URL is invalid.");
return;
}
Console.WriteLine("Successfully Logged out.");
}
else
{
Console.WriteLine("Logout Error" + (int)response.StatusCode + "," + response.ReasonPhrase);
}
}
}
public async void GetProcesses()
{
var handler = new HttpClientHandler();
Cookie ok = new Cookie("Set-Cookie:",strCookietoPass);
handler.CookieContainer.Add(collection);
using (var client = new HttpClient(handler))
{
var builder = new UriBuilder("http://localhost/bonita/API/bpm/process");
builder.Port = 8080;
var query = HttpUtility.ParseQueryString(builder.Query);
query["p"] = "0";
query["c"] = "10";
builder.Query = query.ToString();
Uri uri= new Uri(builder.ToString());
client.BaseAddress = uri;
HttpResponseMessage response = await client.GetAsync(uri.ToString());
if (response.IsSuccessStatusCode)
{
var responseBodyText = await response.Content.ReadAsStringAsync();
if (String.IsNullOrEmpty(responseBodyText))
{
Console.WriteLine("Unsuccessful GetProcesses.Bonita bundle may not have been started, or the URL is invalid.");
return;
}
Console.WriteLine("Successfully GetProcesses:" + responseBodyText);
}
else
{
Console.WriteLine("GetProcesses Error" + (int)response.StatusCode + "," + response.ReasonPhrase);
}
}
}
}
}

I had the same problem (401 errors) for every single non-GET request.
I finally got through this by looking to the CSRF documentation:
http://documentation.bonitasoft.com/7.4?page=csrf-security
(See the "Is there an impact on REST API calls?" section)
After succesfull login, you have to put a special header in your request:
key: X-Bonita-API-Token
value: the one you got after your login (check the relevant cookie)

Related

How to generate bearer token when clicking on the link in email

I want to generate bearer token when someone clicked on the email link, this token contains the identity of the person who clicked on the email link and if person forwarded the email to other person then bearer token should contain identity of forwarded person when he click on the email link(purpose of including identity here is validation of person at server side).
Email link contains service call when clicked it will call service and validate bearer token.
Approve
Appreciate any comments here
I'm generating token after the user verifies OTP. In your case, you don't need to verify anything.
API Method
public async Task<IActionResult> LoginFunction(
[HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = "Account/Login")] HttpRequest req, ILogger log)
{
string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
var accountDto = JsonConvert.DeserializeObject<AccountDto>(requestBody);
log.LogInformation($"ValidateOTP for phoneNumber {accountDto.PhoneNumber}");
var isUserValid = await this.accountService.ValidateOTP(accountDto.PhoneNumber, accountDto.OTP);
if (isUserValid)
{
return (ActionResult)new OkObjectResult(BuildToken(accountDto));
}
return (ActionResult)new NotFoundObjectResult("Invalid OTP");
}
private UserToken BuildToken(AccountDto accountDto)
{
var claims = new[]
{
new Claim(ClaimTypes.MobilePhone, accountDto.PhoneNumber)
};
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("LKM3LKM344NKSFN4KJ345N43KJN4KJFNK")); //read from config
var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
// Expiration time
var expiration = DateTime.UtcNow.AddYears(1);
JwtSecurityToken token = new JwtSecurityToken(
issuer: AppConstraint.TokenIssuer,
audience: AppConstraint.Audience,
claims: claims,
expires: expiration,
signingCredentials: creds);
return new UserToken()
{
Token = new JwtSecurityTokenHandler().WriteToken(token),
Expiration = expiration
};
}
Once you will get token you can store that token to the user's browser and send with each request.
Custom Authorize Attribute Using MrAdvice Aspect
public class AuthorizedAttribute : Attribute, IMethodAsyncAdvice
{
public async Task Advise(MethodAsyncAdviceContext context)
{
try
{
try
{
HttpRequest request = (HttpRequest)context.Arguments[0];
var tokenString = request.Headers[AppConstraint.Authorization].ToString().Split(' ')[1];
JwtSecurityToken token = new JwtSecurityTokenHandler().ReadJwtToken(tokenString);
if (token.ValidTo <= DateTime.Now)
{
throw new SecurityTokenExpiredException("Token has expired");
}
var claimPrincipal = GetIdentityFromToken(tokenString);
request.HttpContext.User = claimPrincipal;
}
catch
{
context.ReturnValue = Task.FromResult<IActionResult>((ActionResult)new UnauthorizedResult());
return;
}
await context.ProceedAsync(); // this calls the original method
}
catch
{
throw;
}
}
private ClaimsPrincipal GetIdentityFromToken(string token)
{
var tokenParams = new TokenValidationParameters()
{
RequireSignedTokens = true,
ValidAudience = AppConstraint.Audience,
ValidateAudience = true,
ValidIssuer = AppConstraint.TokenIssuer,
ValidateIssuer = true,
ValidateIssuerSigningKey = true,
ValidateLifetime = true,
IssuerSigningKey = new SymmetricSecurityKey(System.Text.Encoding.UTF8.GetBytes("LKM3LKM344NKSFN4KJ345N43KJN4KJFNK"))
};
var handler = new JwtSecurityTokenHandler();
var result = handler.ValidateToken(token, tokenParams, out _);
return result;
}
}
Hope this will help to generate and verify your own token.

How to extract data from POST request in azure functions java

I send form data in POST request from angular app to my azure functions who wrriten in java.
the client side look like this:
#Injectable({
providedIn: 'root'
})
export class SendItemToAzureFunctionsService {
private functionURI: string;
constructor(private http: HttpClient) {
this.functionURI = 'https://newsfunctions.azurewebsites.net/api/HttpTrigger-Java?code=k6e/VlXltNs7CmJBu7lmBbzaY4tlo21lXaLuvfG/tI7m/XXXX';
}
// {responseType: 'text'}
sendItem(item: Item){
let body = new FormData();
body.append('title', item.title);
body.append('description', item.description);
body.append('link', item.link);
return this.http.post(this.functionURI, body)
.pipe(
map((data: string) => {
return data;
}), catchError( error => {
return throwError( 'Something went wrong!' );
})
)
}
}
when Item recived to azure functions.
the aim of functions is to send this item in push notifications via firebase to android app.
the azure functions with HTTP trigger look like this:
#FunctionName("HttpTrigger-Java")
public HttpResponseMessage run(#HttpTrigger(name = "req", methods = { HttpMethod.GET,
HttpMethod.POST }, authLevel = AuthorizationLevel.FUNCTION) HttpRequestMessage<Optional<String>> request,
final ExecutionContext context) {
context.getLogger().info("Java HTTP trigger processed a request.");
// Parse query parameter
String itemDetails = request.getBody().get();
if (itemDetails == null) {
return request.createResponseBuilder(HttpStatus.BAD_REQUEST)
.body("Please pass a name on the query string or in the request body").build();
} else {
// ======
String postUrl = "https://fcm.googleapis.com/fcm/send";
HttpClient httpClient = HttpClientBuilder.create().build();
HttpPost post = new HttpPost(postUrl);
post.setHeader("authorization", FIREBAE_AUTH);
post.setHeader("Content-type", "application/json");
JSONObject contentJson = new JSONObject();
contentJson.put("title", "example title");
contentJson.put("description", "example text");
JSONObject pushNotificationJson = new JSONObject();
pushNotificationJson.put("data", contentJson);
pushNotificationJson.put("to", "/topics/newsUpdateTopic");
try {
StringEntity stringEntity = new StringEntity(pushNotificationJson.toString(), "UTF-8");
post.setEntity(stringEntity);
HttpResponse response = httpClient.execute(post);
System.out.println(response.getEntity().getContent().toString());
} catch (IOException var9) {
var9.printStackTrace();
}
// =========
}
return request.createResponseBuilder(HttpStatus.OK)
.body("succeed to send new item in push notification to clients").build();
}
when I am running String itemDetails = request.getBody().get();
I am getting:
------WebKitFormBoundary2gNlxQx5pqyAeDL3
Content-Disposition: form-data; ....
I will be glad to know how to get data item from that?
If you want to parse from-date type data in Azure function with java, you can try to use MultipartStream in SDK org.apache.commons.fileupload to implement it. For example
code
public HttpResponseMessage run(
#HttpTrigger(name = "req", methods = {HttpMethod.GET, HttpMethod.POST}, authLevel = AuthorizationLevel.ANONYMOUS) HttpRequestMessage<Optional<String>> request,
final ExecutionContext context) throws IOException {
context.getLogger().info("Java HTTP trigger processed a request.");
String contentType = request.getHeaders().get("content-type");
String body = request.getBody().get(); // Get request body
String boundary = contentType.split(";")[1].split("=")[1]; // Get boundary from content-type header
int bufSize = 1024;
InputStream in = new ByteArrayInputStream(body.getBytes()); // Convert body to an input stream
MultipartStream multipartStream = new MultipartStream(in, boundary.getBytes(), bufSize, null); // Using MultipartStream to parse body input stream
boolean nextPart = multipartStream.skipPreamble();
while (nextPart) {
String header = multipartStream.readHeaders();
int start =header.indexOf("name=") + "name=".length()+1;
int end = header.indexOf("\r\n")-1;
String name = header.substring(start, end);
System.out.println(name);
multipartStream.readBodyData(System.out);
System.out.println("");
nextPart = multipartStream.readBoundary();
}
return request.createResponseBuilder(HttpStatus.OK).body("success").build();
}
Test. I test with postman
I've used #Jim Xu's code and created a class to get the data in easier way. Here is the gist - https://gist.github.com/musa-pro/dcef0bc23e48227e4b89f6e2095f7c1e

post request in Unirest Java result on a 302 http result

I m training my self on creating a restful server and a desktop java based client.
my backend is Spring Boot based, I have the following controller :
#RestController
#RequestMapping(NiveauAccessController.URL)
public class NiveauAccessController extends GenericController{
public static final String URL = "/acl";
#Autowired
private NiveauAccessRepository niveauAccessRepository;
#PostMapping
private ServerResponse createACL(
#RequestParam("aclTitle") final String aclTitle,
#RequestParam("roles") final List<String> roles
){
if(isSessionValid()){
final MNG_NIVEAU_ACCEE mng_niveau_accee = new MNG_NIVEAU_ACCEE();
mng_niveau_accee.setAclTitle(aclTitle);
List<Role> enumRoles = new ArrayList();
roles.stream().forEach(role->{
enumRoles.add(Role.valueOf(role));
});
mng_niveau_accee.setRoles(enumRoles);
niveauAccessRepository.save(mng_niveau_accee);
initSuccessResponse(mng_niveau_accee);
return serverResponse;
}
initFailLoginResponse();
return serverResponse;
}
.
.
.
}
for my java client I m using this sample code to send a post request over my server :
#FXML
private void doAdd(ActionEvent event) throws UnirestException {
if (titleACL.getText().isEmpty()) {
Alert alert = new Alert(Alert.AlertType.ERROR);
alert.initModality(Modality.WINDOW_MODAL);
alert.initOwner(((Node) event.getSource()).getScene().getWindow());
alert.setContentText("Veuillez remplir le champ");
alert.showAndWait();
titleACL.requestFocus();
return;
}
String title = titleACL.getText();
Predicate<? super JFXCheckBox> selectedCheckboxes = checkbox -> {
return checkbox.isSelected();
};
List<JFXCheckBox> selectedCheckBoxesList = observableCheckBoxes.values().stream().filter(selectedCheckboxes).collect(Collectors.toList());
final List<String> roles = new ArrayList<>();
selectedCheckBoxesList.stream().forEach(checkbox -> {
roles.add(checkbox.getText());
});
HttpResponse<String> asString = Unirest.post(ACL_URL)
.header("accept", "application/json")
.field("aclTitle", title)
.field("roles", roles)
.asString();
System.out.println(asString.getStatus());
System.out.println(asString.getHeaders().values());
if (asString.getStatus() == 200) {
}
}
my output is :
302
[[0], [Thu, 10 May 2018 13:30:05 GMT], [https://localhost:8443/acl]]
I don't understand why I m getting the 302 status code which is for URL redirection.
I m trying to use this post to add data to my database.
What should I do to make my Server accept this request?
havins ssl enabled my request over 8080 got redirection to 8443 this is no issue using a web browser because it will handle redirection but in a javafx client you have to handle the redirect by your self so there is a possible solution
if (asString.getStatus() == 200) {
//your success handler code
}else if (asString.getStatus() == 302) {
// use your Rest api to do the request using the response body
}

steam OpenID authentication without a callback-URL

I am trying how to add a steam logging to my java application .I have try out few OpenID libraries in http://openid.net/developers/libraries, And this is for JOpenID ,
Eg - >
OpenIdManager manager = new OpenIdManager();
manager.setTimeOut(10000);
Endpoint endpoint = manager.lookupEndpoint("http://steamcommunity.com/openid");
System.out.println(endpoint);
Association association = manager.lookupAssociation(endpoint);
System.out.println(association);
String url = manager.getAuthenticationUrl(endpoint, association);
System.out.println("Copy the authentication URL in browser:\n" + url);
System.out.println("After successfully sign on in browser, enter the URL of address bar in browser:");
String ret = url;
HttpServletRequest request = createRequest(ret);
Authentication authentication = manager.getAuthentication(request, association.getRawMacKey(), endpoint.getAlias());
System.out.println(authentication);
Because i am not trying this for web app and I Dont have a callback-URL to use , i have use "easymock"
public HttpServletRequest createRequest(String url) throws UnsupportedEncodingException {
int pos = url.indexOf('?');
if (pos==(-1))
throw new IllegalArgumentException("Bad url.");
String query = url.substring(pos + 1);
String[] params = query.split("[\\&]+");
final Map<String, String> map = new HashMap<String, String>();
for (String param : params) {
pos = param.indexOf('=');
if (pos==(-1))
throw new IllegalArgumentException("Bad url.");
String key = param.substring(0, pos);
String value = param.substring(pos + 1);
map.put(key, URLDecoder.decode(value, "UTF-8"));
}
return (HttpServletRequest) Proxy.newProxyInstance(
Main.class.getClassLoader(),
new Class[] { HttpServletRequest.class },
new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.getName().equals("getParameter"))
return map.get((String)args[0]);
throw new UnsupportedOperationException(method.getName());
}
}
);
}
But I am getting a error saying ,
java.lang.IllegalArgumentException: interface javax.servlet.http.HttpServletRequest is not visible from class loader
at java.lang.reflect.Proxy.getProxyClass0(Proxy.java:487)
at java.lang.reflect.Proxy.newProxyInstance(Proxy.java:722)
and i have ALSO try as the code like in
https://gist.github.com/FernFerret/7692878 too (for Openid4java and spark) but got error when creating Route like in link saying there is no 'Route(String)'
get(new Route("/") {
So how can i Make OpenID authentication with out a Redirect URL ?
Can any one can guide me for a java OpenID Authentication for Steam using "any" OpenID code ?
I just need That returned value( like-> http//steamcommunity.com/openid/id/76561197960435530") informed in
http://steamcommunity.com/dev/
Which is the only value that returns .
Many Thanks For Any inputs !!

GWT Facebook Integration

I am trying to write a server side Facebook Notification service in my GWT app. The idea is that I will run this as a timertask or cron job sort of.
With the code below, I get a login URL, I want to be able to Login programmatically as this is intended to be automated (Headless sort of way). I was gonna try do a submit with HTMLunit but I thought the FB API should cater for this.
Please advice.
public class NotificationServiceImpl extends RemoteServiceServlet implements NotificationService {
/**serialVersionUID*/
private static final long serialVersionUID = 6893572879522128833L;
private static final String FACEBOOK_USER_CLIENT = "facebook.user.client";
long facebookUserID;
public String sendMessage(Notification notification) throws IOException {
String api_key = notification.getApi_key();
String secret = notification.getSecret_key();
try {
// MDC.put(ipAddress, req.getRemoteAddr());
HttpServletRequest request = getThreadLocalRequest();
HttpServletResponse response = getThreadLocalResponse();
HttpSession session = getThreadLocalRequest().getSession(true);
// session.setAttribute("api_key", api_key);
IFacebookRestClient<Document> userClient = getUserClient(session);
if(userClient == null) {
System.out.println("User session doesn't have a Facebook API client setup yet. Creating one and storing it in the user's session.");
userClient = new FacebookXmlRestClient(api_key, secret);
session.setAttribute(FACEBOOK_USER_CLIENT, userClient);
}
System.out.println("Creating a FacebookWebappHelper, which copies fb_ request param data into the userClient");
FacebookWebappHelper<Document> facebook = new FacebookWebappHelper<Document>(request, response, api_key, secret, userClient);
String nextPage = request.getRequestURI();
nextPage = nextPage.substring(nextPage.indexOf("/", 1) + 1); //cut out the first /, the context path and the 2nd /
System.out.println(nextPage);
boolean redirectOccurred = facebook.requireLogin(nextPage);
if(redirectOccurred) {
return null;
}
redirectOccurred = facebook.requireFrame(nextPage);
if(redirectOccurred) {
return null;
}
try {
facebookUserID = userClient.users_getLoggedInUser();
if (userClient.users_hasAppPermission(Permission.STATUS_UPDATE)) {
userClient.users_setStatus("Im testing Facebook With Java! This status is written using my Java code! Can you see it? Cool :D", false);
}
} catch(FacebookException ex) {
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Error while fetching user's facebook ID");
System.out.println("Error while getting cached (supplied by request params) value " +
"of the user's facebook ID or while fetching it from the Facebook service " +
"if the cached value was not present for some reason. Cached value = {}" + userClient.getCacheUserId());
return null;
}
// MDC.put(facebookUserId, String.valueOf(facebookUserID));
// chain.doFilter(request, response);
} finally {
// MDC.remove(ipAddress);
// MDC.remove(facebookUserId);
}
return String.valueOf(facebookUserID);
}
public static FacebookXmlRestClient getUserClient(HttpSession session) {
return (FacebookXmlRestClient)session.getAttribute(FACEBOOK_USER_CLIENT);
}
}
Error message:
[ERROR] com.google.gwt.user.client.rpc.InvocationException: <script type="text/javascript">
[ERROR] top.location.href = "http://www.facebook.com/login.php?v=1.0&api_key=MY_KEY&next=notification";
[ERROR] </script>

Categories