Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

intial import of a warden middleware for github oauth

  • Loading branch information...
commit 628a1c1dd52474bccc3358218d90620bd7868bf3 0 parents
@atmos authored
4 .gitignore
@@ -0,0 +1,4 @@
+coverage
+.bundle
+pkg
+.DS_Store
21 Gemfile
@@ -0,0 +1,21 @@
+source :gemcutter
+
+group :runtime do
+ gem 'warden', '~>0.10'
+ gem 'oauth2', '~>0.0.8'
+ gem 'json', '~>1.4.3'
+end
+
+group :test do
+ gem 'rake'
+ gem 'rspec', '~>1.3.0', :require => 'spec'
+ gem 'rcov'
+ gem 'sinatra', '~>1.0', :require => 'sinatra/base'
+ gem 'webrat', '~>0.7.0'
+ gem 'bundler', '~>0.9.25'
+ gem 'randexp', '>=0.1.4'
+ gem 'addressable', '~>2.1.2'
+ gem 'rack-test', '~>0.5.3', :require => 'rack/test'
+end
+
+# vim:ft=ruby
20 LICENSE
@@ -0,0 +1,20 @@
+Copyright (c) 2010 Corey Donohoe
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
10 README.md
@@ -0,0 +1,10 @@
+warden-github
+=============
+
+A sinatra app the provides a gem that...
+
+Developing
+==========
+ % gem install bundler
+ % bundle install
+ % bundle exec rake
60 Rakefile
@@ -0,0 +1,60 @@
+require 'rake/gempackagetask'
+require 'rubygems/specification'
+require 'date'
+require 'bundler'
+
+task :default => [:spec]
+
+require 'spec/rake/spectask'
+desc "Run specs"
+Spec::Rake::SpecTask.new do |t|
+ t.spec_files = FileList['spec/**/*_spec.rb']
+ t.spec_opts = %w(-fs --color)
+ t.spec_opts << '--loadby' << 'random'
+
+ t.rcov_opts << '--exclude' << 'spec,.bundle,.rvm'
+ t.rcov = ENV.has_key?('NO_RCOV') ? ENV['NO_RCOV'] != 'true' : true
+ t.rcov_opts << '--text-summary'
+ t.rcov_opts << '--sort' << 'coverage' << '--sort-reverse'
+end
+
+GEM = "warden-github"
+GEM_VERSION = "0.0.1"
+AUTHOR = "Corey Donohoe"
+EMAIL = "atmos@atmos.org"
+HOMEPAGE = "http://github.com/atmos/warden-github"
+SUMMARY = "A warden extension that integrates with github oauth"
+
+spec = Gem::Specification.new do |s|
+ s.name = GEM
+ s.version = GEM_VERSION
+ s.platform = Gem::Platform::RUBY
+ s.has_rdoc = true
+ s.extra_rdoc_files = ["LICENSE"]
+ s.summary = SUMMARY
+ s.description = s.summary
+ s.author = AUTHOR
+ s.email = EMAIL
+ s.homepage = HOMEPAGE
+
+ bundle = Bundler::Definition.from_gemfile('Gemfile')
+ bundle.dependencies.each do |dep|
+ next unless dep.groups.include?(:runtime)
+ s.add_dependency(dep.name, dep.version_requirements.to_s)
+ end
+
+ s.require_path = 'lib'
+ s.files = %w(LICENSE README.md Rakefile) + Dir.glob("{lib}/**/*")
+end
+
+Rake::GemPackageTask.new(spec) do |pkg|
+ pkg.gem_spec = spec
+end
+
+desc "create a gemspec file"
+task :make_spec do
+ File.open("#{GEM}.gemspec", "w") do |file|
+ file.puts spec.to_ruby
+ end
+end
+
19 config.ru
@@ -0,0 +1,19 @@
+ENV['RACK_ENV'] ||= 'development'
+
+begin
+ require File.expand_path('../.bundle/environment', __FILE__)
+rescue LoadError
+ require "rubygems"
+ require "bundler"
+ Bundler.setup
+end
+
+Bundler.require(:runtime, :test)
+
+$LOAD_PATH << File.dirname(__FILE__) + '/lib'
+require File.expand_path(File.join(File.dirname(__FILE__), 'lib', 'warden-github'))
+require File.expand_path(File.join(File.dirname(__FILE__), 'spec', 'app'))
+
+run Example.app
+
+# vim:ft=ruby
12 lib/warden-github.rb
@@ -0,0 +1,12 @@
+require 'warden'
+require 'oauth2'
+
+module Warden
+ module Github
+ class GithubMisconfiguredError < StandardError; end
+ end
+end
+
+require 'warden-github/user'
+require 'warden-github/version'
+require 'warden-github/strategy'
48 lib/warden-github/strategy.rb
@@ -0,0 +1,48 @@
+Warden::Strategies.add(:github) do
+ # Need to make sure that we have a pure representation of the query string.
+ # Rails adds an "action" parameter which causes the openid gem to error
+ def params
+ @params ||= Rack::Utils.parse_query(request.query_string)
+ end
+
+ def authenticate!
+ if params['code']
+ begin
+ access_token = oauth_client.web_server.get_access_token(params['code'], :redirect_uri => callback_url)
+ user = JSON.parse(access_token.get('/api/v2/json/user/show'))
+ success!(Warden::Github::Oauth::User.new(user['user'], access_token.token))
+ rescue OAuth2::HTTPError
+ %(<p>Outdated ?code=#{params[:code]}:</p><p>#{$!}</p><p><a href="/auth/github">Retry</a></p>)
+ end
+ else
+ url = oauth_client.web_server.authorize_url(
+ :scope => 'email,offline_access',
+ :redirect_uri => callback_url
+ )
+ throw(:halt, [ 302, {'Location' => url}, [ ]])
+ end
+ end
+
+ private
+ def oauth_client
+ OAuth2::Client.new(env['warden'].config[:github_client_id],
+ env['warden'].config[:github_secret],
+ :site => 'https://github.com',
+ :authorize_path => '/login/oauth/authorize',
+ :access_token_path => '/login/oauth/access_token')
+ end
+
+ def callback_url
+ absolute_url(request, env['warden'].config[:github_callback_url])
+ end
+
+ def absolute_url(request, suffix = nil)
+ port_part = case request.scheme
+ when "http"
+ request.port == 80 ? "" : ":#{request.port}"
+ when "https"
+ request.port == 443 ? "" : ":#{request.port}"
+ end
+ "#{request.scheme}://#{request.host}#{port_part}#{suffix}"
+ end
+end
17 lib/warden-github/user.rb
@@ -0,0 +1,17 @@
+module Warden
+ module Github
+ module Oauth
+ class User < Struct.new(:attribs, :token)
+ extend Forwardable
+
+ def name
+ attribs['name']
+ end
+
+ def email
+ attribs['email']
+ end
+ end
+ end
+ end
+end
5 lib/warden-github/version.rb
@@ -0,0 +1,5 @@
+module Warden
+ module Github
+ VERSION = "0.0.1"
+ end
+end
56 spec/app.rb
@@ -0,0 +1,56 @@
+module Example
+ class App < Sinatra::Base
+ enable :sessions
+ enable :raise_errors
+ disable :show_exceptions
+
+ use Warden::Manager do |manager|
+ manager.default_strategies :github
+ manager.failure_app = BadAuthentication
+
+ manager[:github_secret] = ENV['GH_SECRET'] || 'ed8ff0c54067aefb808dab1ca265865405d08d6f'
+ manager[:github_client_id] = ENV['GH_CLIENT_ID'] || 'ee9aa24b64d82c21535a'
+ manager[:github_callback_url] = '/auth/github/callback'
+ end
+
+ helpers do
+ def ensure_authenticated
+ unless env['warden'].authenticate!
+ throw(:warden)
+ end
+ end
+
+ def user
+ env['warden'].user
+ end
+ end
+
+ get '/' do
+ ensure_authenticated
+ "Hello There, #{user.name}!"
+ end
+
+ get '/auth/github/callback' do
+ ensure_authenticated
+ redirect '/'
+ end
+
+ get '/logout' do
+ env['warden'].logout
+ "Peace!"
+ end
+ end
+
+ class BadAuthentication < Sinatra::Base
+ get '/unauthenticated' do
+ status 403
+ "Unable to authenticate, sorry bud."
+ end
+ end
+
+ def self.app
+ @app ||= Rack::Builder.new do
+ run App
+ end
+ end
+end
17 spec/oauth_spec.rb
@@ -0,0 +1,17 @@
+require File.dirname(__FILE__) + '/spec_helper'
+
+describe "Warden::Github" do
+ it "requesting an url that requires authentication redirects to github" do
+ response = get "/"
+
+ uri = Addressable::URI.parse(response.headers["Location"])
+ uri.should_not be_nil
+ uri.scheme.should eql('https')
+
+ params = uri.query_values
+ params['type'].should eql('web_server')
+ params['scope'].should eql('email,offline_access')
+ params['client_id'].should match(/\w{20}/)
+ params['redirect_uri'].should eql('http://example.org/auth/github/callback')
+ end
+end
24 spec/spec_helper.rb
@@ -0,0 +1,24 @@
+Bundler.require(:default, :runtime, :test)
+
+require File.join(File.dirname(__FILE__), '..', 'lib', 'warden-github')
+require File.join(File.dirname(__FILE__), 'app')
+
+require 'pp'
+
+Webrat.configure do |config|
+ config.mode = :rack
+ config.application_port = 4567
+end
+
+Spec::Runner.configure do |config|
+ config.include(Rack::Test::Methods)
+ config.include(Webrat::Methods)
+ config.include(Webrat::Matchers)
+
+ config.before(:each) do
+ end
+
+ def app
+ Example.app
+ end
+end
Please sign in to comment.
Something went wrong with that request. Please try again.