REST API Bonita 6.x Authentication 401 Unauthorized

1
+4
-1

Hello guys,

i am really new to bonitasoft.

Please help, i am writing my thesis at university and i already spend too much time on this issue and cannot go on because of this problem.

I did installed bonita(didn't need to do any configurations), created organisation and a process and deployed them. Now i want to integrate the bonita engine with a remote custom UI.

I am trying to achieve that with the http-requests. Now i am testing with a browser rest client. For example i want to get the tasks for a user i always get response status 401 Unauthorized. If a run the bonita portal and log in, while a am logged i am getting the right response with the REST client.

I already read: http://documentation.bonitasoft.com/web-rest-api-0

http://community.bonitasoft.com/blog/how-use-bonita-bpm-6-web-rest-api-p...

but i am still getting the 401 status code.

Any help will be appreciated

Comments

Submitted by user11 on Tue, 12/09/2014 - 12:33

hi, how to use rest api in bonita 5.10.2 ? i deployed the war and changed the user and password but it doesn't work ?

Submitted by antoine.mottier on Tue, 12/09/2014 - 14:02

Please create a new topic for your question as this one focus on version 6.

Thanks

9 answers

1
+5
-1

Sorry for my wrong anwser follow this guide and everything should work

login

example url : "http://localhost:8081/bonita/loginservice?username=walter.bates&redirect..."

response Cookie JSESSIONID

for example

"JSESSIONID=FE1AEFEDC60C2C32F970EC2089967781"

call API "GetProcess"

example url: "http://localhost:8081/bonita/API/bpm/process?p=0&c=10"

To the header you must add

Content-Type : application/json

and the response cookie from the login

You should get as response the installed Process

Regards

1
+2
-1

This works for .Net 2.0 C# but has some interesting things to check.

  1. WebClient wc = new WebClient();
  2. wc.Proxy = WebRequest.GetSystemWebProxy();
  3. //wc.Headers[HttpRequestHeader.AcceptEncoding] = "gzip, deflate";
  4. string strLogin = wc.DownloadString("http://localhost:8080/bonita/loginservice?username=walter.bates&password=bpm&redirect=false");
  5.  
  6. wc.Headers[HttpRequestHeader.Cookie] = wc.ResponseHeaders[HttpResponseHeader.SetCookie].ToString();
  7. string strCookie = wc.ResponseHeaders[HttpResponseHeader.SetCookie].ToString();
  8.  
  9. 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

  1. 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:

  1. strLogin="" // the body of the response must be empty
  2. strCookie="JSESSIONID=4F67F134840A2C72DBB968D53772FB22; Path=/bonita; HttpOnly"

For the successful getProcesses on the previous example you pass the header you got from login ->

  1. 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. Actually I spend a lot of time to find out that my app doesn't work because of the lowercase!

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);
            }

        }
    }
}

}

1
+1
-1

This does not solve any of the problems when calling the Bonita Rest API using client-side scripting (e.g. AngularJS): - configuration need for cross-site accept on tomcat: tricky, but it works - reading the Set-Cookie in javascript: impossible because it is set as 'httpOnly', so there is no javascript access! Setting httpOnly to false in the Tomcat context.xml results in NO Set-Cookie being sent at all. So this is a dead end!

Oh, and the web api documentation is nice, but not nearly comprehensive enough to get anything working properly. This is sad as the Bonita modeler is by far the easiest to use of all BPMN engines I have tried

Any comments?

Comments

Submitted by grigoriadis on Thu, 12/04/2014 - 09:29

I fully agree with you "the web api documentation is not nearly comprehensive enough to get anything working properly".

Submitted by philippe.ozil on Mon, 12/08/2014 - 10:10

Hi,

You should not read the cookie directly, you should call this API method to retrieve all session information: GET http://localhost:8080/bonita/API/identity/system/session/0

Also, if you wish to speed up your Angular developments with the Bonita REST API, please take a look at this project: https://github.com/rodriguelegall/ngBonita

Cheers,

Philippe

Submitted by yves.vanderhaeghen on Tue, 12/09/2014 - 15:44

Unfortunately ngBonita gives exactly the same error: 401!

The login service posts a request with the form data: username:walter.bates password:bpm redirect:false A set cookie is returned with JSESSIONID xxxxxxx73A4

The call to the unused session returns {}

The http-Get to obtain the processes fails with 401, obviously as its JSESSIONID is not set to the new cookie.

Back to square one!!!

Submitted by kaykay on Thu, 10/08/2015 - 19:47

yes, i am struggling with this issue for past couple days and not sure how to resolve.

1
+1
-1

Hi

please try to login with standard username = "walter.bates" and password = "bpm". If everything works fine you will get an http header with code = "200" and a JSESSIONID which you should use if you call "getProcess" for example.

By the way if i call "getProcess" include JSESSIONID i get the same error code like you (401) :D

Regards

Comments

Submitted by user11 on Fri, 08/29/2014 - 17:34

hi, i am using ajax to get data from bonita, this is works whith an application in the same server but doesn't work from another server. how can i write the server side part ? thank you

Submitted by kyle.johnson on Thu, 10/09/2014 - 18:27

"By the way if i call "getProcess" include JSESSIONID i get the same error code like you (401) "

Did this ever get resolved? Please help.

Submitted by kyle.johnson on Mon, 10/13/2014 - 16:34

Hello. Can I get a response please?

Submitted by ryan.dever on Mon, 10/13/2014 - 19:55

You might be running into CORS issues. Please see this thread for more information: http://community.bonitasoft.com/answers/cors-preflight-issues-firefox-an.... There is currently no solution but reading the thread my shed some light on your problem.

You may also want to research Cross Origin Resource Sharing if you have not already: http://www.w3.org/TR/cors/

Submitted by juhi.chowhan on Tue, 11/11/2014 - 10:28

Damyan I dont knw anythng about WEB REST API in bonita but I am supposed to that can you please tell me how you did?

Submitted by antoine.mottier on Thu, 11/20/2014 - 11:03

I would give below instructions to use REST UI Client in order to perform a REST request without doing any previous authentication in a web browser.

First you need to do the authentication request in order to get a jsessionid useful for any subsequent API call:

  • Download the REST request provided here and load it into REST UI client
  • If needed change the default username and password set in "HTTP Request" section in "Body" tab
  • Run the request (button on the right of the URL)
  • Go to "HTTP Response" section, under "Headers" tab, select the "Set-Cookie" line
  • Right-click on the line and select "Copy Cookie Name-Value Pairs". Value is for example: JSESSIONID: 2D4489DECE129DFA77DC75FF25429077

Now you are ready to run any REST queries. For example we will get the list of deployed processes definitions:

  • Open the request you can get here.
  • Go to "HTTP Request" section, "Cookie" tab
  • Click on the button on the right ("Multi-insert")
  • Paste copied cookie name-value pairs (e.g. JSESSIONID: 2D4489DECE129DFA77DC75FF25429077)
  • Ignore warning message
  • Run the request (button on the right of the URL)
  • In "HTTP Response" section check answer in "Body" tab
Submitted by grigoriadis on Thu, 11/20/2014 - 11:06

I have exactly the same problem. I have read the documentation and had many tests (including what you say in your comments) and I login succesfully to bonita through WEB REST API and I get the JSESSIONID but I cannot continue to get the processes (401 error). I did another test though. I log in through the browser (not my application) and I find the JSESSIONID from the browser tools, I copy it and use it to my application and I get succesfully the processes. So I am trying to figure out a solution.

Submitted by grigoriadis on Wed, 12/17/2014 - 14:00

I changed the comment and made it an answer - see above. I apologise! first time here!

1
+1
-1

Hi,

thanks for helping.

I forgot to mention this:

I did this step, but the response is always status ok(200) and a html login form with the error: "Unable to log in. Please check your username and password"

username: restuser
password: restbpm

I did created such an user in my organization with admin rights. But maybe this should be done somewhere else?

best regards

1
+1
-1

Hi,

do you complete these step successfully?

"Calls to the Web REST API require you to first log in as a user registered in the Engine database."

Regards

1
0
-1

1
0
-1

Damyan I dont knw anythng about WEB REST API in bonita but I am supposed to that can you please tell me how you did?

Comments

Submitted by antoine.mottier on Thu, 11/20/2014 - 10:19

Documentation provides helpful guidelines:

I'll recommend you take a look to the REST documentation section .

1
0
-1

Thanks Spectraflex,

finally that helped.

Mostly i tried to pass the user data as headers and not as url-parameter.

i appreciate your help

Notifications