Permalink
Browse files

Renamed Rack::OAuth2::Server::Admin to just Rack::OAuth2::Admin.

Checked in config.ru, I use this for testing the Web console.
  • Loading branch information...
assaf committed Nov 9, 2010
1 parent f16b9a5 commit a632c479ec1332fd771e3faa0ffc72f33a503b1c
Showing with 288 additions and 244 deletions.
  1. +7 −0 CHANGELOG
  2. +7 −7 README.rdoc
  3. +1 −1 VERSION
  4. +6 −6 bin/oauth2-server
  5. +38 −0 config.ru
  6. +224 −0 lib/rack/oauth2/admin.rb
  7. +4 −1 lib/rack/oauth2/server.rb
  8. +0 −227 lib/rack/oauth2/server/admin.rb
  9. +1 −2 test/setup.rb
View
@@ -1,3 +1,10 @@
+2010-11-09 version 1.4.3
+
+Renamed Rack::OAuth2::Server::Admin to just Rack::OAuth2::Admin.
+
+Checked in config.ru, I use this for testing the Web console.
+
+
2010-11-09 version 1.4.2
Fix to commend line tool to properly do authentication.
View
@@ -386,29 +386,29 @@ client ID/secret. For example, for Rails add this to +config/environment.rb+:
Rails::Initializer.run do |config|
. . .
config.after_initialize do
- config.middleware.use Rack::OAuth2::Server::Admin.mount
- Rack::OAuth2::Server::Admin.set :client_id, "4dca20453e4859cb000007"
- Rack::OAuth2::Server::Admin.set :client_secret, "981fa734e110496fcf667cbf52fbaf03"
+ config.middleware.use Rack::OAuth2::Admin.mount
+ Rack::OAuth2::Admin.set :client_id, "4dca20453e4859cb000007"
+ Rack::OAuth2::Admin.set :client_secret, "981fa734e110496fcf667cbf52fbaf03"
end
end
For Sinatra, Padrino and other Rack-based applications, you'll want to mount
like so (e.g. in +config.ru+):
Rack::Builder.new do
- map("/oauth/admin") { run Rack::OAuth2::Server::Admin }
+ map("/oauth/admin") { run Rack::OAuth2::Admin }
map("/") { run MyApp }
end
- Rack::OAuth2::Server::Admin.set :client_id, "4dca20453e4859cb000007"
- Rack::OAuth2::Server::Admin.set :client_secret, "981fa734e110496fcf667cbf52fbaf03"
+ Rack::OAuth2::Admin.set :client_id, "4dca20453e4859cb000007"
+ Rack::OAuth2::Admin.set :client_secret, "981fa734e110496fcf667cbf52fbaf03"
Next, open your browser to http://example.com/oauth/admin, or wherever you
mounted the console.
Another option, +template_url+ allows you to link access token identities to
URLs in your application, using the substitution variable "{id}". For example:
- Rack::OAuth2::Server::Admin.set :template_url, "https://example.com/accounts/{id}"
+ Rack::OAuth2::Admin.set :template_url, "https://example.com/accounts/{id}"
The OAuth Web console is a single-page client application that operates by
accessing the OAuth API. The API is mounted at /oauth/admin/api (basically /api
View
@@ -1 +1 @@
-1.4.2
+1.4.3
View
@@ -73,19 +73,19 @@ For example:
Rails 2.x, add the following to config/environment.rb:
config.after_initialize do
- config.middleware.use Rack::OAuth2::Server::Admin.mount "#{uri.path}"
- Rack::OAuth2::Server::Admin.set :client_id, "#{client.id}"
- Rack::OAuth2::Server::Admin.set :client_secret, "#{client.secret}"
+ config.middleware.use Rack::OAuth2::Admin.mount "#{uri.path}"
+ Rack::OAuth2::Admin.set :client_id, "#{client.id}"
+ Rack::OAuth2::Admin.set :client_secret, "#{client.secret}"
end
Sinatra, Padrino and other Rack applications, mount the console:
Rack::Builder.new do
- map("#{uri.path}") { run Rack::OAuth2::Server::Admin }
+ map("#{uri.path}") { run Rack::OAuth2::Admin }
map("/") { run MyApp }
end
- Rack::OAuth2::Server::Admin.set :client_id, "#{client.id}"
- Rack::OAuth2::Server::Admin.set :client_secret, "#{client.secret}"
+ Rack::OAuth2::Admin.set :client_id, "#{client.id}"
+ Rack::OAuth2::Admin.set :client_secret, "#{client.secret}"
The console will authorize access by redirecting to
https://#{uri.host}/oauth/authorize
View
@@ -0,0 +1,38 @@
+$: << File.dirname(__FILE__) + "/lib"
+require "rack/oauth2/server"
+Rack::OAuth2::Server.database = Mongo::Connection.new["test"]
+
+class Authorize < Sinatra::Base
+ register Rack::OAuth2::Sinatra
+ get "/oauth/authorize" do
+ <<-HTML
+ <h1>#{oauth.client.display_name} wants to access your account.</h1>
+ <form action="/oauth/grant" method="post"><button>Let It!</button>
+ <input type="hidden" name="auth" value="#{oauth.authorization}">
+ </form>
+ HTML
+ end
+
+ post "/oauth/grant" do
+ oauth.grant! params[:auth], "Superman"
+ end
+end
+# NOTE: This client must exist in your database. To get started, run:
+# oauth-server setup --db test
+# And enter the URL
+# http://localhost:3000/oauth/admin
+# Then plug the client ID/secret you get instead of these values, and run:
+# thin start
+# open http://localhost:3000/oauth/admin
+Rack::OAuth2::Admin.set :client_id, "4cd9cbc03321e8367d000001"
+Rack::OAuth2::Admin.set :client_secret, "c531191fb208aa34d6b44d6f69e61e97e56abceadb336ebb0f2f5757411a0a19"
+Rack::OAuth2::Admin.set :template_url, "http://localhost:3000/accounts/{id}"
+app = Rack::Builder.new do
+ map "/" do
+ run Authorize.new
+ end
+ map "/oauth/admin" do
+ run Rack::OAuth2::Admin.new
+ end
+end
+run app.to_app
View
@@ -0,0 +1,224 @@
+require "sinatra/base"
+require "json"
+require "rack/oauth2/sinatra"
+
+module Rack
+ module OAuth2
+ class Admin < ::Sinatra::Base
+
+ class << self
+
+ # Rack module that mounts the specified class on the specified path,
+ # and passes all other request to the application.
+ class Mount
+ class << self
+ def mount(klass, path)
+ @klass = klass
+ @path = path
+ @match = /^#{Regexp.escape(path)}(\/.*|$)?/
+ end
+
+ attr_reader :klass, :path, :match
+ end
+
+ def initialize(app)
+ @pass = app
+ @admin = self.class.klass.new
+ end
+
+ def call(env)
+ path = env["PATH_INFO"].to_s
+ script_name = env['SCRIPT_NAME']
+ if path =~ self.class.match && rest = $1
+ env.merge! "SCRIPT_NAME"=>(script_name + self.class.path), "PATH_INFO"=>rest
+ return @admin.call(env)
+ else
+ return @pass.call(env)
+ end
+ end
+ end
+
+ # Returns Rack handle that mounts Admin on the specified path, and
+ # forwards all other requests back to the application.
+ #
+ # @param [String, nil] path The path to mount on, defaults to
+ # /oauth/admin
+ # @return [Object] Rack module
+ #
+ # @example To include admin console in Rails 2.x app
+ # config.middleware.use Rack::OAuth2::Server::Admin.mount
+ def mount(path = "/oauth/admin")
+ mount = Class.new(Mount)
+ mount.mount Admin, "/oauth/admin"
+ mount
+ end
+
+ end
+
+ # Need client ID to get access token to access this console.
+ set :client_id, nil
+ # Need client secret to get access token to access this console.
+ set :client_secret, nil
+ # Use this URL to authorize access to this console. If not set, goes to
+ # /oauth/authorize.
+ set :authorize, nil
+ # Map access token identity to URL on your application, by replacing
+ # "{id}" with the token identity (e.g. "http://example.com/user/{id}")
+ set :template_url, nil
+
+ # Number of tokens to return in each page.
+ set :tokens_per_page, 100
+ set :public, ::File.dirname(__FILE__) + "/admin"
+ set :method_override, true
+ mime_type :js, "text/javascript"
+ mime_type :tmpl, "text/x-jquery-template"
+
+
+ helpers Rack::OAuth2::Sinatra::Helpers
+ extend Rack::OAuth2::Sinatra
+ use Rack::OAuth2::Server
+
+ # Force HTTPS except for development environment.
+ before do
+ redirect request.url.sub(/^http:/, "https:") unless request.scheme == "https" || settings.development?
+ end
+
+
+ # -- Static content --
+
+ # It's a single-page app, this is that single page.
+ get "/" do
+ send_file settings.public + "/views/index.html"
+ end
+
+ # Service JavaScript, CSS and jQuery templates from the gem.
+ %w{js css views}.each do |path|
+ get "/#{path}/:name" do
+ send_file settings.public + "/#{path}/" + params[:name]
+ end
+ end
+
+
+ # -- Getting an access token --
+
+ # To get an OAuth token, you need client ID and secret, two values we
+ # didn't pass on to the JavaScript code, so it has no way to request
+ # authorization directly. Instead, it redirects to this URL which in turn
+ # redirects to the authorization endpoint. This redirect does accept the
+ # state parameter, which will be returned after authorization.
+ get "/authorize" do
+ redirect_uri = "#{request.scheme}://#{request.host}:#{request.port}#{request.script_name}"
+ query = { :client_id=>settings.client_id, :client_secret=>settings.client_secret, :state=>params[:state],
+ :response_type=>"token", :scope=>"oauth-admin", :redirect_uri=>redirect_uri }
+ auth_url = settings.authorize || "#{request.scheme}://#{request.host}:#{request.port}/oauth/authorize"
+ redirect "#{auth_url}?#{Rack::Utils.build_query(query)}"
+ end
+
+
+ # -- API --
+
+ oauth_required "/api/clients", "/api/client/:id", "/api/client/:id/revoke", "/api/token/:token/revoke", :scope=>"oauth-admin"
+
+ get "/api/clients" do
+ content_type "application/json"
+ json = { :list=>Server::Client.all.map { |client| client_as_json(client) },
+ :tokens=>{ :total=>Server::AccessToken.count, :week=>Server::AccessToken.count(:days=>7),
+ :revoked=>Server::AccessToken.count(:days=>7, :revoked=>true) } }
+ json.to_json
+ end
+
+ post "/api/clients" do
+ begin
+ client = Server::Client.create(validate_params(params))
+ redirect "#{request.script_name}/api/client/#{client.id}"
+ rescue
+ halt 400, $!.message
+ end
+ end
+
+ get "/api/client/:id" do
+ content_type "application/json"
+ client = Server::Client.find(params[:id])
+ json = client_as_json(client, true)
+
+ page = [params[:page].to_i, 1].max
+ offset = (page - 1) * settings.tokens_per_page
+ total = Server::AccessToken.count(:client_id=>client.id)
+ tokens = Server::AccessToken.for_client(params[:id], offset, settings.tokens_per_page)
+ json[:tokens] = { :list=>tokens.map { |token| token_as_json(token) } }
+ json[:tokens][:total] = total
+ json[:tokens][:page] = page
+ json[:tokens][:next] = "#{request.script_name}/client/#{params[:id]}?page=#{page + 1}" if total > page * settings.tokens_per_page
+ json[:tokens][:previous] = "#{request.script_name}/client/#{params[:id]}?page=#{page - 1}" if page > 1
+ json[:tokens][:total] = Server::AccessToken.count(:client_id=>client.id)
+ json[:tokens][:week] = Server::AccessToken.count(:client_id=>client.id, :days=>7)
+ json[:tokens][:revoked] = Server::AccessToken.count(:client_id=>client.id, :days=>7, :revoked=>true)
+
+ json.to_json
+ end
+
+ put "/api/client/:id" do
+ client = Server::Client.find(params[:id])
+ begin
+ client.update validate_params(params)
+ redirect "#{request.script_name}/api/client/#{client.id}"
+ rescue
+ halt 400, $!.message
+ end
+ end
+
+ delete "/api/client/:id" do
+ Server::Client.delete(params[:id])
+ 200
+ end
+
+ post "/api/client/:id/revoke" do
+ client = Server::Client.find(params[:id])
+ client.revoke!
+ 200
+ end
+
+ post "/api/token/:token/revoke" do
+ token = Server::AccessToken.from_token(params[:token])
+ token.revoke!
+ 200
+ end
+
+ helpers do
+ def validate_params(params)
+ display_name = params[:displayName].to_s.strip
+ halt 400, "Missing display name" if display_name.empty?
+ link = URI.parse(params[:link].to_s.strip).normalize rescue nil
+ halt 400, "Link is not a URL (must be http://....)" unless link
+ halt 400, "Link must be an absolute URL with HTTP/S scheme" unless link.absolute? && %{http https}.include?(link.scheme)
+ redirect_uri = URI.parse(params[:redirectUri].to_s.strip).normalize rescue nil
+ halt 400, "Redirect URL is not a URL (must be http://....)" unless redirect_uri
+ halt 400, "Redirect URL must be an absolute URL with HTTP/S scheme" unless
+ redirect_uri.absolute? && %{http https}.include?(redirect_uri.scheme)
+ unless params[:imageUrl].nil? || params[:imageUrl].to_s.empty?
+ image_url = URI.parse(params[:imageUrl].to_s.strip).normalize rescue nil
+ halt 400, "Image URL must be an absolute URL with HTTP/S scheme" unless
+ image_url.absolute? && %{http https}.include?(image_url.scheme)
+ end
+ { :display_name=>display_name, :link=>link.to_s, :image_url=>image_url.to_s, :redirect_uri=>redirect_uri.to_s }
+ end
+
+ def client_as_json(client, with_stats = false)
+ { "id"=>client.id.to_s, "secret"=>client.secret, :redirectUri=>client.redirect_uri,
+ :displayName=>client.display_name, :link=>client.link, :imageUrl=>client.image_url,
+ :url=>"#{request.script_name}/api/client/#{client.id}",
+ :revoke=>"#{request.script_name}/api/client/#{client.id}/revoke",
+ :created=>client.created_at, :revoked=>client.revoked }
+ end
+
+ def token_as_json(token)
+ { :token=>token.token, :identity=>token.identity, :scope=>token.scope, :created=>token.created_at,
+ :expired=>token.expires_at, :revoked=>token.revoked,
+ :link=>settings.template_url && settings.template_url.gsub("{id}", token.identity),
+ :revoke=>"#{request.script_name}/api/token/#{token.token}/revoke" }
+ end
+ end
+
+ end
+ end
+end
@@ -2,7 +2,7 @@
require "rack/oauth2/server/errors"
require "rack/oauth2/server/utils"
require "rack/oauth2/server/helper"
-require "rack/oauth2/server/admin"
+require "rack/oauth2/admin"
module Rack
@@ -14,6 +14,9 @@ class Server
# Same as gem version number.
VERSION = IO.read(::File.expand_path("../../../VERSION", ::File.dirname(__FILE__)))
+ # Backward compatible.
+ Admin = Rack::OAuth2::Admin
+
class << self
# Return AuthRequest from authorization request handle.
def get_auth_request(authorization)
Oops, something went wrong.

0 comments on commit a632c47

Please sign in to comment.