Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OAuth examples #153

Merged
merged 13 commits into from
Jan 2, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions examples/oauth2/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.env
81 changes: 81 additions & 0 deletions examples/oauth2/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
Running APIcast with OAuth
==========================

The API Gateway has a dependency on Redis when adding OAuth support.

In this case, `docker-compose` has to be run in order to start up all of the required components.

The command to do so is:

```shell
docker-compose up -d
```

from the directory containing the `docker-compose.yml` file (in this case `/examples/oauth2`).

The `-d` flag starts the containers up in detached mode, if you want to see the output when starting the containers, you should omit this.

In order for the command to run successfully, you will also need a `.env` file with the following content (substituting the THREESCALE_PORTAL_ENDPOINT value with your own):

```
# URI to fetch gateway configuration from. Expected format is: https?://[password@]hostname
THREESCALE_PORTAL_ENDPOINT=https://access_token@example-admin.3scale.net

# Redis host. Used to store access tokens.
REDIS_HOST=redis
```

The docker compose file spins up 4 services:

1. APIcast
2. Redis
3. A very simple Authorization Server (auth-server) written in Ruby
4. A sample Client to request an Authorization code and exchange that for an Access Token

3scale setup
------------

To get this working with a 3scale instance the following conditions should be met:

1. Self-managed deployment type and OAuth authentication method should be selected
2. *OAuth Authorization Endpoint* on the Integration page needs to be configured, e.g. if you're running the auth-server app on localhost this would be `http://localhost:3000/auth/login`
3. Set the *Public Base URL* in the Production section of the Integration page to the gateway host e.g `http://localhost:8080`
4. An application created in 3scale configured with its **Redirect URL** to point to the `client.rb` instance, e.g `http://localhost:3001/callback`

Once you have APIcast configured to point to your local OAuth testing instance (Gateway + Auth Server), and you have run `docker-compose up` to start all of the required components, you can navigate to your client instance (in this case `client.rb` running on `localhost:3001`) to request an access token.

client.rb
---------

A very simple Sinatra app acting as a Client, running on `http://localhost:3001`.

The app will display a page where you can enter a `client_id`, `redirect_uri` and `scope` to request an authorization code.

The Authorization URL targeted will be the `/authorize` endpoint on your API Gateway instance, e.g `localhost:8080/authorize`
The Access Token URL targeted will be the `/oauth/token` endpoint on your API Gateway instance. e.g `localhost:8080/oauth/token`

Both these values are built in to the client, however, the Gateway host can be overwritten by adding a `.env` file under the `client` directory and specifying the gateway host in the `GATEWAY` environment variable (in format `<host>:<port>`), otherwise this will default to `localhost:8080`

Once an authorization code is returned back to the app, you can exchange that for an access token by additionally providing a client secret.

### Requesting an authorization code

You can then click **Authorize** under "Step 1: Request Authorization Code" to initiate the access token request process.

### Exchanging authorization code for an access token

When the authorization code is returned, you can enter in your `client_id` and `client_secret` under "Step 2: Exchange Authorization Code for Access Token" and click **Get Token** to request an access token.

auth-server.rb
--------------

A very simple Sinatra app acting as an Authorization Server, running on `http://localhost:3000`.

The app will display a log in page (`/auth/login`) which will accept any values for username and password.
Once logged in, a consent page will be displayed to accept or deny the request.

The authorization server will callback APIcast (running on `http://localhost:8080`) to issue an authorization code on request acceptance and the `redirect_uri` directly on denial.

Once the Authorization Code is sent to the redirect URL (client callback endpoint in this case) we exchange this for an access token as per the instructions above under "Exchanging authorization code for an access token."

The `auth-server.rb` code for running this example using `docker-compose` locally assumes that the Gateway host is running on `localhost:8080`. You can always override this by adding a `.env` file in the `auth-server` directory and referencing this within your `docker-compose.yml` file, same as for `client.rb`.
2 changes: 2 additions & 0 deletions examples/oauth2/auth-server/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
.dockerignore
Dockerfile
6 changes: 6 additions & 0 deletions examples/oauth2/auth-server/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
FROM ruby:2.4.0-onbuild

MAINTAINER Maria Pilar Guerra Arias <pguerra@redhat.com>

EXPOSE 3000
CMD ["bundle", "exec", "rackup", "--port", "3000", "--host", "0.0.0.0"]
4 changes: 4 additions & 0 deletions examples/oauth2/auth-server/Gemfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
source 'https://rubygems.org'

gem 'sinatra'
gem 'dotenv'
22 changes: 22 additions & 0 deletions examples/oauth2/auth-server/Gemfile.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
GEM
remote: https://rubygems.org/
specs:
dotenv (2.1.1)
rack (1.6.5)
rack-protection (1.5.3)
rack
sinatra (1.4.7)
rack (~> 1.5)
rack-protection (~> 1.4)
tilt (>= 1.3, < 3)
tilt (2.0.5)

PLATFORMS
ruby

DEPENDENCIES
dotenv
sinatra

BUNDLED WITH
1.13.6
45 changes: 45 additions & 0 deletions examples/oauth2/auth-server/auth-server.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
require 'sinatra'

set :bind, '0.0.0.0'

GATEWAY = ENV['GATEWAY'] || "localhost:8080"
nginx_redirect_uri = "http://#{GATEWAY}/callback?" #nginx callback
enable :sessions
set :session_secret, '*&(^B234'

get("/") do
erb :root
end

get("/auth/login") do
session[:client_id] = params[:client_id]
session[:redirect_uri] = params[:redirect_uri]
session[:scope] = params[:scope]
session[:state] = params[:state]
session[:pre_token] = params[:tok]

erb :login
end

post("/auth/login") do
redirect "/consent"
end

get("/consent") do
@client_id = session[:client_id]
@scope = session[:scope]

erb :consent
end

get("/authorized") do
callback = "#{nginx_redirect_uri}state=#{session[:state]}&redirect_uri=#{session[:redirect_uri]}"
puts callback
redirect callback
end

get("/denied") do
callback = "#{session[:redirect_uri]}#error=access_deniedt&error_description=resource_owner_denied_request&state=#{session[:state]}"
puts callback
redirect callback
end
5 changes: 5 additions & 0 deletions examples/oauth2/auth-server/config.ru
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
require_relative 'auth-server'
require 'dotenv'

Dotenv.load
run Sinatra::Application
Loading