How do I secure a Java REST service using Drupal? - security

I am creating a web application that uses the Drupal 7 Content Management System. The web pages heavily use JQuery and AJAX.
The AJAX calls hit REST services, which are actually implemented using JAVA. Apache is running Drupal 7 and is configured to pass any calls to the REST urls through to the Java EE server (Jboss AS7). Everything is over SSL.
I need to Authorise and Authenticate calls to the REST services, and access the username or ID of the person currently logged-in to Drupal from the Java app. The question is... how...
As the AJAX calls are made to the same Apache server (rather than to a separate server etc), everything happens within the same http session, so I'm hoping this will be quite easy.
Things I've thought-of:
Configure a java security interceptor that calls a custom (locally
accessed only) drupal service that somehow reads the session id and
returns the logged-in username
create a "dumb" drupal REST service to act as a gateway for all of my REST calls, which authorises/ authenticates then injects the username before passing-through to the Java backend service
The article at https://lists.wisc.edu/read/messages?id=7777296#7777296 made me wonder if I could get-away with calling a Drupal service (just at the start of each Java service session) that takes a Drupal sessionID and returns the current user and his roles. I could configure it in my Java service so it would reperform this call every x seconds or y calls to check for role changes or logouts.
How does everyone else do it? This must be a common problem to solve isn't it? If not, what do you do instead to securely access authenticated services over AJAX? I'd rather not introduce a second user control process in addition to Drupal unless it's unavoidable. DRY :)
Thank you - this has me stumped!

Looking at what you are doing and trying to keep things as simple as possible, I would go for a variation of the first option. This is basically what the current node.js module does although it does it with unique authorization tokens. The workflow is something like this:
When a logged in user loads a page, a unique token is generated and stored in the Drupal database and sent to the browser
When the browser goes to connect to the node.js server it sends the auth token along with the request
The node.js server, upon receiving the request with token for the first time, will connect to a web service on the Drupal site and verify that the token is valid and send back any info about the user, and what roles/etc they have.
The node.js server then stores this internally for future requests, so that it doesn't have to ping the Drupal site for each request.
When a user logs out of Drupal, Drupal makes a direct request to the node.js server asking it to delete the token for that user.
Sounds like basically swapping your java app for node.js this should be pretty doable, with the advantage that it can scale well if you split this to multiple servers in the future.

Related

Secure way to transmit data from one web app to another in user context

Our application is a Single Page App built with Angular and ASP.NET Core.
We have to integrate another web app which we will integrate in an iframe in our app. This app has to send data back to our application after the user finished his work.
I need to make sure, i can relate the data coming from this application to an authenticated user starting the operation in our app in a secure way.
Those were the options i thought in realizing the interface:
Generate a unique token in our application which knows about the related user and gets passed to the other application. The other application transmits this token along with it's other data back to our application and we can check this token on our backend to find out if it's a legitimate request and also relate it to a user.
Store cookies after authenticating the user in our app, so the other app could just post the data to our endpoint and the cookies make sure, the call takes place in the authenticated user's context. Also we would probably have to allow CORS from this site to make this work.
Use a non-http-based middleware (message broker) to connect the systems in a way, which keeps data transfer out of the browser.
Transmit the Bearer token from our application to the other application, so the other application can make an authenticated call to our application backend.
CORS would have to be activated as well for the other app's origin.
However i'm a bit concerned about the security implications this could have.
Which way would you suggest? Or would you suggest a completely other way of achieving the goal?
Thank you very much for any advise!
Number 2 and 4 will both have potential security issues. Passing authentication contexts between different applications should be avoided, instead each application should be authenticated independently.
Number 3 would add complexity to your architecture while bringing little to no benefit for your use case - message brokers are not trivial to configure and operate. I would also question why two apps need to be integrated in the client via and iFrame but then are somehow able to share a message broker.
Number 1 for me is the cleanest option from your ideas. Consider however, you will need to pass this token somehow in the client which may open security holes. Think about the negative implications of what could happen, should a nefarious 3rd party get access to this token.
In your place I would question why an iFrame. Would it be possible for your app to provide the UI and instead communicate with this other application over an API?

Setup API that only your webserver can see it

So I want to have nginx serve up my react app that uses an API that is setup to make all the API calls for me. I want to do this so I can guard my API key and secret. So the API server is running on port 9001 and my react app is making api calls to to http://localhost:9001/api/v1/token. It works just fine. The issue I have is, how can I stop someone from doing the following to get a token?
curl -X POST --header "referer: http://localhost:8081" -i http://localhost:8081/api/v1/token
Thanks
If what you're asking is how you allow only your react app to use your API server, then the answer is you can't really.
Any request made from the browser has to be made to a server that can be reached lots of other ways (such as your Curl example). You can't allow only requests made from your React code and disallow all other attempts to talk to your API server because at the lowest level, these are all just http requests. Any determined hacker can just watch what the browser sent from your React app and make an http request that looks just like it. This is a fundamental design characteristic of how apps in a web browser work.
That said, there are some things you can do to "protect" your API server from abuse.
1. Require some form of account or authentication. This will at least require a hacker to make an account in your system and use that account to access your API server (more on this later).
2. Implement rate limiting so that an individual account (detected based on the credentials in the previous step) is only allowed certain frequency or pattern or access. At the very least this protects your API server from being overly abused by one bad actor.
3. Implement abuse control. If one particular account is regularly abusing the API server (hitting rate limit controls and generally using way more resources on your API server than any reasonable normal browser user ever would), then you can ban that account.
Services such as Google maps implement all three of the above in their efforts to protect the integrity of their API servers.
There are other techniques such as embedding an ever changing token into the web page that is then required with each subsequent call to the API server, but a determined hacker will just scrape the token from the web page and then use it until it expires so this is really just another obstacle for the hacker to get around, not an actual roadblock.

Magento to NodeJS via REST APIs using OAuth

I'm trying to call one of Magento REST APIs (say products api) from a NodeJS application using a regular HTTP Request. I know that Magento APIs requires OAuth to authenticate the user/application, and this is where I'm a bit lost.
With Magento or any OAuth application, the end-user who is using the app has to click "Authorize" in order for that application to receive the token, and then the application will be able to communicate directly with Mangento APIs.
In my case, we are talking about 2 servers, Magento and NodeJS, that will talk to each other. So There is no user involve to sort of "Click" the authorize button and validate the auth request.
The point of what I'm trying to achieve is grab product data from Magento, store it in a DB, then make some changes, after that make it accessible via NodeJS REST APIs. (That is a hard requirement and I can't change it).
My question is, Do we have to write custom Magento REST APIs that doesn't require OAuth, or maybe require the regular basic HTTP Authentication (username/password). Or there is a way to use OAuth and authenticate my Node application directly?
I hope my question is clear, if not please let me know and I will try to fix it. Thanks!
After wrestling with a similar situation, I decided to use Magento's SOAP API. All you have to do as far as authentication goes is to set up an API user in the Magento backend and then use the username/password in your API calls (I think, it's been awhile). Not sure if this fits your use case but it saved me a lot of OAuth headache.

OpenID authentication on AppEngine and non-AppEngine subdomains

I have a main website running on AppEngine. It's on a subdomain like main.example.com. This main application is a content portal for our customers. It offers an Ajax application built on YUI. Customers can upload data to it. Users authenticate using Federated Login.
The Ajax application on it allows users to process the data previously uploaded. To do it it should use an webservice running on other subdomain like service.example.com. The webservice does not run on AppEngine but on our services - it's CPU heavy and built on other set of technologies. It would need to download the data on main application - but the downloading service - like everything on the main application - is behind the authentication wall.
I could programatically always allow the service to download wharever it wishes but I think this can turn into a major security problem.
How can I reuse the OpenID authentication "token" to allow it (the service) to appears to the main application as the authenticated user so it can download data? Or If I can do this what would be the best way to accomplish what I intend to do?
You can't really reuse the authentication token. What you should use is something akin to OAuth, though since you control both ends you can make it somewhat simpler:
Generate a shared secret, accessible by both main.example.com and service.example.com
When a user accesses service.example.com for the first time (no authentication cookie), redirect them to main.example.com/auth?continue=original_url (where original_url is the URL they attempted to access)
When you receive a request to main.example.com/auth, first log the user in the regular way (if they're not already). Then, take their user ID or other relevant credentials, and generate an HMAC from them, using the shared secret you established in step 1. Redirect the user to service.example.com/finish_auth, passing the computed HMAC, the authentication details such as user ID, and any parameters you were passed in such as the continue URL.
When you receive a request to service.example.com/finish_auth, compute the HMAC as above, and check it matches the passed in one. If it does, you know the request is a legitimate one. Set an authentication cookie on service.example.com containing any relevant details, and redirect the user back to their original URL.
This sounds complicated, but it's fairly straightforward in implementation. This is a standard way to 'pass' credentials between mutually trusting systems, and it's not unlike what a lot of SSO systems use.

What methods can be used to secure web services?

I'm interested to know what methods people use to secure their webservices from unauthorized web service consumers.
There is a protocol specifically for web services security WS-Security. I've used parts of it in the past but at the time there was not a lot of support for it in .Net so it was a lot of work.
Currently with .Net I use SOAP Extension Headers. I have one web service call to authenticate and get a session token and then include that token in a SOAP header for every subsequent call, somewhat similar to this example. Of course all the request must travel over TLS to keep them from being compromised.
I usually require either a user id/password to be sent each time, or return a token from the first authenticated connection that can be used subsequently.
Nothing fancy. Pretty similar to standard web app login.
I've used both SOAP headers and method parameters to pass user credentials -- .NET makes using the SOAP headers pretty easy, but I had issues with this using Java (several months back). I also do some IP-based filtering if the service is not intended for client (browser) use, but rather from backend web servers. Public, browser consumable web services are often protected by session cookies -- i.e, requires a valid logon to the web site, then the standard session authentication mechanism is used for requests via AJAX to web services.
You can use network appliances such as IBM's DataPower or Vordel if you don't want to handle in your own application.

Resources