Anyone using REST Adapter w/ AngularJS?

Posted by bronco on 13-Sep-2014 12:40

Hi,

Before I write a lengthy question, is anyone using AngularJS in combination with the REST Adapter? I have some issues with REST calls after a succesful login via OERealm.

thanks

All Replies

Posted by Jean Richert on 15-Sep-2014 10:58

Anyone following this forum may have working experience with AngularJS and/with  the REST Adapter that could share with Bronco?

Posted by agent_008_nl on 18-Sep-2014 08:19

Zeker een klus bij tie kinetics Bronco?

Not using this but by accident I saw these:

dcinglis.wordpress.com/.../display-openedge-data-in-an-angularjs-web-app

github.com/.../commits

Maybe david inglis can help you. My 100 euro's please.

Posted by bronco on 18-Sep-2014 14:01

The basic pattern is easy. Once you're trying trying to authenticate to the REST adapter, which is reverse proxied, and try to do that from JavaScript thing get a little bit more complicated. CORS stuff I suppose, but I haven't been able to work myself through the details.

[mention:5a647afc67ec4e118db4fd9337f8a264:e9ed411860ed4f2ba0265705b8793d05] : the answer to your question in Dutch is "nee".

Posted by bronco on 18-Sep-2014 15:25

btw, I my hurry today I overlooked the most important piece of the link mentioned above. Contacting Davis Inglis might not be such a bad idea. Thanks.

Posted by Aliaksandr Tarasevich on 18-Sep-2014 15:39

We use AngularJS, make sure you enable "requests with credentials" (somewhere in module config):

$httpProvider.defaults.withCredentials = true;


Posted by bronco on 19-Sep-2014 07:07

Thank [mention:771e2065c3da41b5b2749e090c5a2e62:e9ed411860ed4f2ba0265705b8793d05]. Doing this from the config is much cleaner, I passed as an argument the $http.get function.

What really "bites" me in this case is that this is returned (in the header):

Set-Cookie: JSESSIONID=1524622920BCA23CA647C3E2475DF364; Path=/restapi/; HttpOnly

HttpOnly? Hmm, no script access. I guess I have to dig around in the document Michael Jacobs posted a while ago to see how to allow script access as well. I presume this has to be set some where in the REST config.

Posted by Aliaksandr Tarasevich on 19-Sep-2014 07:43

It's safer to keep session cookie from JS access. You don't really need it (if you want to keep track of session status write http interceptor and flip isLoggedIn flag in $rootScope back and forth based on error status from server).

Posted by Michael Jacobs on 19-Sep-2014 07:45

You can control the 'HttpOnly' Cookie option at either the server level (for all web applications) or at the individual web application level via the <context> attribute 'useHttpOnly=false'.   I would not recommend this being set at the server level unless you are assured that your web application will forever be the only web application running.   I'd look at implementing this in a web application specific META-INF/context.xml file.

Once the 'HttpOnly' option is off in the cookie, then see if your JS client can see it.

Posted by bronco on 19-Sep-2014 07:56

Thanks for response, suggesting altering HttpOnly wasn't exactly correct.

What I'm trying to achieve is after a successful login to do a second call to get some data from the REST adapter (not an uncommon pattern). After this login I receive the Set-Cookie header mentioned above. If I do the second call (fetching data) I get a 401, not authorized. My assumption is that the cookie should be sent to the server (as one of the headers) but that is not the case (checked via Fiddler) and I have no clue why.

Posted by bronco on 19-Sep-2014 08:01

What might be relevant is that I setup Apache as a http server in between. Apache redirect the calls from (in this case) http://localhost/ to http://localhost:8980/

Background:

This since I don't want my clients (Angular) talk to the REST adapter directly. If I got this to work, I might put node.js in between as well, to do some nice middleware stuff (websockets etc). For websockets I might have to change to nginx, which suits Node better.

edit: removed some excessive use of "as well" 

Posted by Aliaksandr Tarasevich on 19-Sep-2014 08:58

Is there any chance you're mixing domains between calls? Tthis would explain the fact that you use withCredentials and see SET-COOKIE, but don't see this COOKIE in the next request.

Posted by Michael Jacobs on 19-Sep-2014 09:27

OK.  Your primary task is to get your client to automatically echo the JSESSIONID cookie back to the server where it will be used to grant you access to the REST resources.  The number of hops between your client and the backend REST service can be variable.  I can tell you that when the backend REST service issues a SET-COOKIE named JSESSIONID, it will require that COOKIE returned or it will begin a new client authentication process.

The httponly will only provide you client code access to the cookie.   So, as you say, that will not help you.

Posted by bronco on 19-Sep-2014 13:31

Fixed it! What I failed to realize is that when one receives a cookie like:

Set-Cookie: JSESSIONID=1524622920BCA23CA647C3E2475DF364; Path=/restapi/; HttpOnly

It is only valid when the subsequent calls are made to /restapi/... Due to my url rewriting configured in Apache the request goes to /data/ which is transformed by Apache to (:8980)/restapi/... in my case.

The challenge is to be able to overcome this on the REST Adapter config, without knowing what the rewriting on Apache side is. 

Posted by bronco on 19-Sep-2014 23:45

And to finalize matters. What I've been trying to do is hide the rather long REST adapter url's by something shorter. The method I chose is setting up a web server (Apache, nginx possible too) to act as a reverse proxy. This setup not only shortens your url's, but it hides all the other Tomcat stuff (port 8980 for example) from the outside world.

ProxyPass         /data  http://localhost:8980/restapi/rest/restapi/router

ProxyPassReverse  /data  http://localhost:8980/restapi/rest/restapi/router

So I want my data calls to go to http(s)://<server-name/data. This works like a charm without authentication. When you turn on authentication cookies come into play. The cookie I got returned at first was:

Set-Cookie: JSESSIONID=1524622920BCA23CA647C3E2475DF364; Path=/restapi/; HttpOnly

The path stuff tells the browser to only send the cookie (the JSESSIONID stuff) back to the server when a call is made to /restapi. Now I just setup Apache to rewire things via /data/ so when calling /data, the cookie is not sent and as a consequence I'm making an unauthorized call. The final piece in this puzzle is to let Apache rewrite the cookie path as well:

ProxyPassReverseCookiePath /restapi /data

Since it took me some time to get this real world example to work I thought I might share the solution as well.

Next challenge: put node.js in between as well, and switch to nginx since this web server matches the architecture of node better.

Posted by Michael Jacobs on 20-Sep-2014 04:28

Bronco,

That is really valuable information, and thank you for sharing!

In your research for this, did you consider or test a configuration where you allowed the Apache web server to do the authentication and pass the resulting user-id down to Tomcat and the REST service to use?

Not that is is any better than the solution you found, just different and was curious about whether it was tried.

Thanks

Posted by bronco on 20-Sep-2014 10:20

Thanks Michael, good to hear it is appreciated. I haven't tried the setup your mentioning, mostly because I try to keep the amount of responsibilities for the web server as low as possible. Reverse proxying and serving static content basically. What I will try however, and that's where node.js comes into play, is authentication via Facebook (for example) and OAuth type of scenario's.I'm not really sure but how to generate the client principles if I authenticate via a 3rd party, but I haven't looked into the details yet.

Posted by Michael Jacobs on 21-Sep-2014 04:33

Perhaps I can assist by providing some information about how the REST service generates a Client-Principal and sends it to an AppServer.   From that you may be able to use some more magic and get all the pieces the way you need them.

The first thing to know is that Client-Principals are generated by the REST service's Spring Security framework.   When it sees an authenticated user, by virtue of Spring generating a client security token, it does a simple conversion to a Client-Principal object and passes it to the AppServer via the connection's ClientPrincipal property.  (The default case anonymous generates a security token for user 'anonymous', which is interpreted as no user login and does not generate or send a Client-Principal to the AppServer )

A Spring Security token can be generated by either SSO (or what I will refer to as SSO) or Direct Login methods.   Direct Login means that the Spring Security framework physically authenticates a user-id & Password to some source (file, LDAP/AD, OE AppServer, DB, ...).  The SSO means that an external authentication process Spring Security is configured to recognize has physically authenticated the user-id/password and has passed the authenticated user-id to Spring Security.   Examples of using external authentication processes is: Tomcat 'container', Apache/IIS via the AJP13 connector, Rollbase 3.1.   The first two would start with using the Spring Security 'container' configuration file.

Hope that helps

Posted by bronco on 22-Sep-2014 09:32

Thanks for this info! I'm not really sure when I'm going to work on this part again. My first focus is creating a presentation for the EMEA PUG Challenge.

This thread is closed