I have an app that I'm writing which authenticates against an Oauth 2.0 authorisation server. I'd like to test the parts that are accessible only after you've logged in but the Oauth server is an external dependency that complicates and make brittle my tests.
Any suggestions on how I should go about this? What the industry practices for something like this? My gut feel is to somehow mock out the server so that it allows access to the protected resources.
In case it matters, this is a Python webapp written using Flask.
I am using a custom oauth server which will run on my own domain and while it's possible to add some kind of sandboxing functionality as FoxMask has suggested, I'd much prefer being able to run the test without requiring an extra server running.
From the consumer (i.e. your application) side, the OAuth2 process can be separated in two parts:
the redirect from your application to the OAuth2 provider's "authorize" URL
the exchange of the "code" returned by the OAuth2 provider for an access token
For #1 all you need to test is that when you invoke the route that starts the authentication process the response returned is a redirect to the OAuth2 provider. This is easily accomplished with Flask's test client. The response should have a status code of 302 and a "Location" header set to the authorize URL for your OAuth2 provider. Note that you do not need to provider to be up, you are just testing that the response is a redirect, but you do not need to actually redirect.
Testing for #2 is a little bit more involved. Your Flask app has a special URL that is designated as the "redirect URL" for the OAuth2 provider to send you back the authorization code. You can just invoke this URL with the Flask test client passing a mock code and that has no issue.
The problem is that in the view function that handles your redirect URL you need to invoke the OAuth2 provider to exchange the auth code for an access token, and this is done synchronously. To prevent this transaction to happen you have to check app.config['TESTING'] and in that case skip the actual request and replace it with a fake response that includes a mock access token.
From then on you will need to also fake any additional calls into the OAuth2 provider that send the access token to request data.
If you are using an OAuth2 client library in your Flask app it may be easier to create the mock provider without having to create testing exceptions in your application. In my case I'm using rauth, and for this I have created a subclass of the OAuth2Service class that overrides the proper methods and responds with mock data that I have captured from a real session. Then in my test setup I just create the mock service and the application is fooled into thinking it is talking to a real server.
I hope this helps.
Related
I would like to write a simple desktop application for personal use that uses the Spotify Web API to build playlists.
As far as I can tell, however, there's no way to use the API without providing a callback URI, which I don't have, seeing as I don't have a domain or server of any kind (other than my personal computer).
Is there a way to use the API without a URI?
If not, what is the best way to set up a callback URI? I don't have much of any experience working with web applications or client / server stuff, and the APIs I've used in the past haven't required any kind of callback.
Some background first, this answer became a bit longer than what I anticipated.
You need an access token. There are three ways to retrieve an access token; Authentication Code flow, Client Credentials flow, and Implicit Grant flow. These are all part of the oAuth 2.0 specification, each with its own purpose.
Since you're going to modify a user's account, you need that user's permission. Now, if you didn't do any actions that required user permissions, you could've used the Client Credentials flow. That's probably the easiest flow to learn since it just requires a request from your server to Spotify's server, and the response contains an access token. No callback/redirect URI is necessary.
As I'm sure you've read, the Authentication Code flow and Implicit Grant flow both require a callback URI. This is because a flow that includes a user, and the callback URI is where Spotify redirects the user after they have entered their password on Spotify's site.
The Authentication Code flow and Implicit Grant flow has benefits and drawbacks. Access tokens retrieved through the Authentication Code flow can be refreshed, but both return tokens that are valid for one hour. This means that a user that's authenticating using the Implicit Grant flow must reauthenticate after an hour. However, the Authentication Code flow does require some backend work, since it needs to make a request to exchange a code given from Spotify's server for an access token. The Implicit Grant flow is more straight forward - you get the access token and off you go.
The callback URI can be a localhost address, so if your desktop application would spin up a web server locally you could handle the callback on the same machine that the application is running on. (It's probably a good idea to not run the web server on port 80 since that might be used by something else.)
There's skeleton code for each of this authentication flows available on Github, see web-api-auth-examples. Read more about the flows in our Authorization Guide. If you choose to run a web server on the user's machine, I recommend that you use the Implicit Grant flow since that doesn't include any server-to-server requests, so you won't have to expose your client_secret exposed in the code. (As opposed to the Authorization Code flow.)
Also, since you're coding in Python, I recommend that you have a look at spotipy, a wrapper around the Web API packed with convenient methods that'll save you some time. If you do go ahead with the Implicit Grant flow, you should have a look at spotify-web-api-js, which has a similar purpose. Note that these wrappers are not at all required to work with the Web API but they'll make your life easier.
I have a website and I need to test it with 250 users. However, I am using google login via OAuth2. The website is hosted on Google App Engine.
I am stuck at this login part. After we log in we get and access token from Google that is passed to Google APIs via the Authorization: Bearer header. We use the access token in the application to get user details and access other google apps for that user. I don't know how to get that access token using my external script.
One option is to mock / stub this part of your application out during testing. For instance, you can provide a certain header that tells your application that you're in test mode and instead of calling the real google APIs, it calls a mock API instead. If your application is setup for dependency injection this could be trivial, otherwise, it may involve monkey-patching or similar.
Another option is to use an OAuth2 Service Account and acquire access tokens for a bunch of users in a test Google Apps domain. Your test script can do this and then just pass the access tokens just as a client normally would.
I'm working on an API registration and authentication service application using python. Developers will be able to register their application (domain name of the application) and a random API key will be generated for the registered application.
Next, the registered application will send the API key to the API service with each API request. API server will authenticate the domain of the incoming request with the passed API key to confirm that the request is valid. I'm using Forwarded Host to validated the domain name of the API request, however it doesn't work as in some cases (when the opened page is the first page), Forward Host comes blank.
Are there a better approach to authenticate the request or any changes required in the API registration process to reliably authenticate the request? Some pointers will be helpful.
Using Authorization proxy
Samples are "3scale.net", offering free tier, other commercial solutions exist too.
Open source solution I am aware of is ApiAxle, which is much simpler, but still very useful.
The proxy takes care of managing access keys and forwards request back to real application only in case, it is really to be served.
Using Authorization service
Another solution is to have some internal service evaluating set of client provided keys (providerid, appid, accesskey, ...) are authrized or not. For this purpose, you have to:
set up authorization service
modify your code by adding 2-3 lines at the top of each call calling the authentication service.
Sample code for 3scale is here: https://github.com/3scale/3scale_ws_api_for_python
Conclusions
Authentication proxy makes the application simple and not bothering about who is asking. This can be advantage until your application needs to know who is asking.
Authentication service requires changing your code.
I want to have a front-end server where my clients can connect, and depending on the client, be redirected (transparently) to another Flask application that will handle the specific client needs (eg. there can be different applications).
I also want to be able to add / remove / restart those backend clients whenever I want without killing the main server for the other clients.
I'd like the clients to:
not detect that there are other servers in the backend (the URL should be the same host)
not have to reenter their credentials when they are redirected to the other process
What would be the best approach?
The front-end server that you describe is essentially what is known as a reverse proxy.
The reverse proxy receives requests from clients and forwards them to a second line of internal servers that clients cannot reach directly. Typically the decision of which internal server to forward a request to is made based on some aspect of the request URL. For example, you can assign a different sub-domain to each internal application.
After the reverse proxy receives a response from the internal server it forwards it on to the client as if it was its own response. The existence of internal servers is not revealed to the client.
Solving authentication is simple, as long as all your internal servers share the same authentication mechanism and user database. Each request will come with authentication information. This could for example be a session cookie that was set by the login request, direct user credentials or some type of authentication token. In all cases you can validate logins in the same way in all your applications.
Nginx is a popular web server that works well as a reverse proxy.
Sounds like you want a single sign-on setup for a collection of service endpoints with a single entry point.
I would consider deploying all my services as Flask applications with no knowledge of how they are to be architected. All they know is all requests for resources need some kind of credentials associated with them. The manner you pass those credentials can vary. You can use something like the FAS Flask Auth Plugin to handle authentication. Or you can do something simpler like package the credentials provided to your entry service in the HTTP headers of the subsequent requests to other services. Flask.request.headers in your subsequent services will give you access to the right headers to pass to your authentication service.
There are a lot of ways you can go when it comes to details, but I think this general architecture should work for you.
I have an application that has a "private" REST API; I use RESTful URLs when making Ajax calls from my own webpages. However, this is unsecure, and anyone could make those same calls if they knew the URL patterns.
What's the best (or standard) way to secure these calls? Is it worth looking at something like OAuth now if I intend to release an API in the future, or am I mixing two separate strategies together?
I am using Google App Engine for Python and Tipfy.
Definitely take a look at OAuth
It is quickly becoming the "de-facto" standard for securing REST APIs and a lot of big companies are using it, including Google, Twitter and Facebook just to name a few.
For Python on GAE you have two options:
The most straightforward way (IMHO) is using David Larlet's library for OAuth Support in Django available on BitBucket.
But since you're not using Django, maybe you want to take a look at the python-oauth2 library that's available on GitHub, and is considered the most up-to-date and unit-tested implementation of OAuth for Python 2.4+.
Either way I think you'd be much better using OAuth than rolling your own service security solution.
Securing a javascript client is nearly impossible; at the server, you have no fool-proof way to differentiate between a human using a web browser and a well-crafted script.
SSL encrypts data over the wire but decrypts at the edges, so that's no help. It prevents man-in-the-middle attacks, but does nothing to verify the legitimacy of the original client.
OAuth is good for securing requests between two servers, but for a Javascript client, it doesn't really help: anyone reading your javascript code can find your consumer key/secret, and then they can forge signed requests.
Some things you can do to mitigate API scraping:
Generate short-lived session cookies when someone visits your website. Require a valid session cookie to invoke the REST API.
Generate short-lived request tokens and include them in your website HTML; require a valid request token inside each API request.
Require users of your website to log in (Google Accounts / OpenID); check auth cookie before handling API requests.
Rate-limit API requests. If you see too many requests from one client in a short time frame, block them.
OAuth would be overkill in your current scenario (potentially insecure), in that it's designed to authorize a third party service to have access to resources on behave of the user.
Securing AJAX request via an authorized user
AFAICT, you are in control of the client, resources and authentication; so you only need to secure access to the URL's and possibly the communication between client and server via SSL [2].
So, use Tipfy's auth extension to secure your URLs:
from tipfy import RequestHandler, Response
from tipfy.ext.auth import AppEngineAuthMixin, user_required
class MyHandler(RequestHandler, AppEngineAuthMixin):
#user_required
def get(self, **kwargs):
return Response('Only logged in users can see this page.')
Securing AJAX request without an authorized user
If a user is unknown, then one could apply CSRF preventions to help protect the REST service from being called from an "unauthorized" client. Tipfy has this built-in to it's WTForms extension, but it's not AJAX. Instead, the session extension could be used to apply an "authenticity_token" to all calls, that needs to be verified on the server.