Skip to content
This repository was archived by the owner on Oct 16, 2019. It is now read-only.

foto #55

Open
wants to merge 57 commits into
base: move-to-one-oh
Choose a base branch
from
Open

foto #55

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
07508cf
Merge pull request #35 from atmos/move-to-one-oh
atmos Sep 4, 2013
80d1105
add a license, fixes #36
atmos Sep 12, 2013
24bd3d4
grab the first x-forwarded-proto header
atmos Mar 24, 2014
3dc4449
version bump
atmos Mar 24, 2014
d838a8d
try this now too
atmos Mar 24, 2014
2554d4a
minor fixups
atmos Mar 25, 2014
14afa81
explain changes in the changelog too
atmos Mar 25, 2014
dae6b8e
Merge pull request #37 from atmos/handle-multiple-x-forwarded-protos
atmos Mar 25, 2014
94bab24
Make avatar_url available through the user object
eugeneius Sep 7, 2014
13ebd61
Merge pull request #40 from eugeneius/avatar_url
atmos Sep 8, 2014
fc62d88
cut a version 1.0.2 gem
atmos Oct 1, 2014
0f7a4d2
Cache team memberships
fphilipe Dec 13, 2014
4c74bea
Merge pull request #42 from fphilipe/cache-team-memberships
atmos Dec 13, 2014
44afe6c
cut version 1.0.3
atmos Dec 13, 2014
6e3d4d8
appease the rspec gods
atmos Jan 7, 2015
2d9cccc
encrypt user objects in the session
atmos Jan 8, 2015
31db5f6
dumb down the verifier stuff
atmos Jan 8, 2015
84291a3
use a custom serializer for sensitive info
atmos Jan 8, 2015
ff7941c
use json marshaling instead of marshaling objects
atmos Jan 12, 2015
bd1596a
document defaults for securely storing api tokens
atmos Jan 13, 2015
601e171
version bump
atmos Jan 13, 2015
8b4d76c
Merge pull request #43 from atmos/message-verifier
atmos Jan 13, 2015
70876d1
explicitly require json for verifier marshaling
atmos Jan 15, 2015
b617bec
add basic single sign out support for github properties
atmos Feb 13, 2015
9c8dc8b
fixup sso examples in the simple app
atmos Feb 13, 2015
398fec0
do a version bump for sso support
atmos Feb 13, 2015
3bba8e5
fixup tests
atmos Feb 18, 2015
69cd3bf
move browser verified at out of the user model
atmos Feb 18, 2015
96d598d
make an easily included module for sso support
atmos Feb 18, 2015
0fb6eb6
another pre-release
atmos Feb 18, 2015
c48ffdf
use the helper methods
atmos Feb 18, 2015
6ca97cd
use the helper methods
atmos Feb 18, 2015
77f74ff
cut a 1.2.0 release
atmos Feb 18, 2015
c786e48
provide docs for the sso session valid stuff
atmos Feb 18, 2015
f53ab66
use the helper method instead of accessing the session directly
atmos Feb 18, 2015
e7a9fa2
simplify the readme
atmos Feb 18, 2015
a97811e
use a meaningful name for the test description
atmos Feb 18, 2015
3e9aa5f
Merge pull request #46 from atmos/single-sign-out
atmos Feb 18, 2015
c617777
Improve JSON serialization compatibility of User
fphilipe Apr 14, 2016
bbe3131
Merge pull request #49 from fphilipe/improve-json-serialization-compa…
atmos Apr 20, 2016
bee9e2a
update ruby versions we care about
atmos Apr 20, 2016
a2e4b6a
can't install on 1.8.7, don't care
atmos Apr 20, 2016
8082f75
remove ruby versions that no longer work on travis
atmos Apr 20, 2016
c450606
cut 1.3.0
atmos Apr 20, 2016
b2ebac2
Always use strings
sethvargo Jul 16, 2016
d1cd127
Bump version
sethvargo Jul 16, 2016
65aae45
Yank ruby-head
sethvargo Jul 16, 2016
59c4ce7
Merge pull request #50 from sethvargo/sethvargo/strings
atmos Jul 16, 2016
63d3549
Persist membership cache between requests
fphilipe May 13, 2017
242b75b
Upgrade to rspec 3.6
fphilipe May 13, 2017
0a2d8fa
Use new symbol syntax
fphilipe May 13, 2017
4a5af45
Replace old debugger gems by byebug
fphilipe May 13, 2017
d716c62
Update ruby version on Travis
fphilipe May 13, 2017
8f121d4
Bump version
fphilipe May 13, 2017
9a3c1f5
Merge pull request #54 from fphilipe/maintenance
atmos May 15, 2017
db408b2
Merge branch 'master' into fix-membership-cache
atmos May 15, 2017
366f9ce
Merge pull request #53 from fphilipe/fix-membership-cache
atmos May 15, 2017
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
9 changes: 1 addition & 8 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,10 +1,3 @@
language: ruby
rvm:
- 1.8.7
- 1.9.2
- 1.9.3
- jruby-18mode # JRuby in 1.8 mode
- jruby-19mode # JRuby in 1.9 mode
- rbx-18mode
- ree
- ruby-head
- 2.4.1
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,16 @@
v1.2.0 2015/02/18

* Implement single sign out for cookie sessions of GitHub properties

v1.0.3 2014/12/13

* Reintroduce membership caching to reduce API hits for validating team membership.

v1.0.1 2014/03/24
-----------------

* Handle multiple X-Forwarded-Proto headers when comma delimited

v1.0.0 2013/09/03
-----------------

Expand Down
3 changes: 1 addition & 2 deletions Gemfile
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
source "https://rubygems.org"

gem 'debugger', :platforms => :ruby_19, :require => false
gem 'ruby-debug', :platforms => :ruby_18, :require => false
gem 'byebug', require: false

# Specify your gem's dependencies in warden-github.gemspec
gemspec
42 changes: 37 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,14 +48,19 @@ use Warden::Manager do |config|
config.failure_app = BadAuthentication
config.default_strategies :github

config.scope_defaults :default, :config => { :scope => 'user:email' }
config.scope_defaults :admin, :config => { :client_id => 'foobar',
:client_secret => 'barfoo',
:scope => 'user,repo',
:redirect_uri => '/admin/oauth/callback' }
config.scope_defaults :default, config: { scope: 'user:email' }
config.scope_defaults :admin, config: { client_id: 'foobar',
client_secret: 'barfoo',
scope: 'user,repo',
redirect_uri: '/admin/oauth/callback' }

config.serialize_from_session { |key| Warden::GitHub::Verifier.load(key) }
config.serialize_into_session { |user| Warden::GitHub::Verifier.dump(user) }
end
```

The two serialization methods store the API token in the session securely via the `WARDEN_GITHUB_VERIFIER_SECRET` environmental variable.

### Parameters

The config parameters and their defaults are listed below.
Expand Down Expand Up @@ -116,6 +121,7 @@ user.id # => The GitHub user id.
user.login # => The GitHub username.
user.name
user.gravatar_id # => The md5 email hash to construct a gravatar image.
user.avatar_url
user.email # => Requires user:email or user scope.
user.company

Expand All @@ -137,6 +143,32 @@ If you're looking for an easy way to integrate this into a Sinatra or Rails appl
- [sinatra_auth_github](https://github.com/atmos/sinatra_auth_github)
- [warden-github-rails](https://github.com/fphilipe/warden-github-rails)

## Single Sign Out

OAuth applications owned by the GitHub organization are sent an extra browser parameter to ensure that the user remains logged in to github.com. Taking advantage of this is provided by a small module you include into your controller and a before filter. Your `ApplicationController` should resemble something like this.


```ruby
class ApplicationController < ActionController::Base
include Warden::GitHub::SSO

protect_from_forgery with: :exception

before_filter :verify_logged_in_user

private

def verify_logged_in_user
unless github_user && warden_github_sso_session_valid?(github_user, 120)
request.env['warden'].logout
request.env['warden'].authenticate!
end
end
end
```

You can also see single sign out in action in the example app.

## Additional Information

- [warden](https://github.com/hassox/warden)
Expand Down
2 changes: 1 addition & 1 deletion Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ require 'rubygems/specification'
require 'date'
require 'bundler'

task :default => [:spec]
task default: [:spec]

require 'rspec/core/rake_task'
desc "Run specs"
Expand Down
15 changes: 1 addition & 14 deletions config.ru
Original file line number Diff line number Diff line change
@@ -1,19 +1,6 @@
ENV['RACK_ENV'] ||= 'development'

begin
require File.expand_path('../.bundle/environment', __FILE__)
rescue LoadError
require "rubygems"
require "bundler"
Bundler.setup
end

begin
require 'debugger'
rescue LoadError
require 'ruby-debug'
end

require "bundler/setup"
require 'warden/github'

if ENV['MULTI_SCOPE_APP']
Expand Down
10 changes: 5 additions & 5 deletions example/multi_scope_app.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@ class MultiScopeApp < BaseApp
enable :inline_templates

GITHUB_CONFIG = {
:client_id => ENV['GITHUB_CLIENT_ID'] || 'test_client_id',
:client_secret => ENV['GITHUB_CLIENT_SECRET'] || 'test_client_secret'
client_id: ENV['GITHUB_CLIENT_ID'] || 'test_client_id',
client_secret: ENV['GITHUB_CLIENT_SECRET'] || 'test_client_secret'
}

use Warden::Manager do |config|
config.failure_app = BadAuthentication
config.default_strategies :github
config.scope_defaults :default, :config => GITHUB_CONFIG
config.scope_defaults :admin, :config => GITHUB_CONFIG.merge(:scope => 'user,notifications')
config.scope_defaults :default, config: GITHUB_CONFIG
config.scope_defaults :admin, config: GITHUB_CONFIG.merge(scope: 'user,notifications')
end

get '/' do
Expand All @@ -26,7 +26,7 @@ class MultiScopeApp < BaseApp
end

get '/admin/login' do
env['warden'].authenticate!(:scope => :admin)
env['warden'].authenticate!(scope: :admin)
redirect '/'
end

Expand Down
30 changes: 25 additions & 5 deletions example/simple_app.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,42 @@

module Example
class SimpleApp < BaseApp
include Warden::GitHub::SSO

enable :inline_templates

GITHUB_CONFIG = {
:client_id => ENV['GITHUB_CLIENT_ID'] || 'test_client_id',
:client_secret => ENV['GITHUB_CLIENT_SECRET'] || 'test_client_secret',
:scope => 'user'
client_id: ENV['GITHUB_CLIENT_ID'] || 'test_client_id',
client_secret: ENV['GITHUB_CLIENT_SECRET'] || 'test_client_secret',
scope: 'user'
}

use Warden::Manager do |config|
config.failure_app = BadAuthentication
config.default_strategies :github
config.scope_defaults :default, :config => GITHUB_CONFIG
config.scope_defaults :default, config: GITHUB_CONFIG
config.serialize_from_session { |key| Warden::GitHub::Verifier.load(key) }
config.serialize_into_session { |user| Warden::GitHub::Verifier.dump(user) }
end

def verify_browser_session
if env['warden'].user && !warden_github_sso_session_valid?(env['warden'].user, 10)
env['warden'].logout
end
end

get '/' do
erb :index
end

get '/profile' do
verify_browser_session
env['warden'].authenticate!
erb :profile
end

get '/login' do
verify_browser_session
env['warden'].authenticate!
redirect '/'
end
Expand Down Expand Up @@ -66,7 +78,7 @@ def self.app
@@ index
<% if env['warden'].authenticated? %>
<h2>
<img src='http://gravatar.com/avatar/<%= env['warden'].user.gravatar_id %>.png?r=PG&s=50' />
<img src='<%= env['warden'].user.avatar_url %>' width='50' height='50' />
Welcome <%= env['warden'].user.name %>
</h2>
<% else %>
Expand All @@ -84,4 +96,12 @@ def self.app
<dd><%= env['warden'].user.team_member?(632) %></dd>
<dt>GitHub Site Admin:</dt>
<dd><%= env['warden'].user.site_admin? %></dd>
<% if env['warden'].user.using_single_sign_out? %>
<dt>GitHub Browser Session ID</dt>
<dd><%= env['warden'].user.browser_session_id %></dd>
<dt>GitHub Browser Session Valid</dt>
<dd><%= warden_github_sso_session_valid?(env['warden'].user, 10) %></dd>
<dt>GitHub Browser Session Verified At</dt>
<dd><%= Time.at(warden_github_sso_session_verified_at) %></dd>
<% end %>
</dl>
5 changes: 5 additions & 0 deletions lib/warden/github.rb
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
require 'json'
require 'warden'
require 'octokit'

require 'warden/github/sso'
require 'warden/github/user'
require 'warden/github/oauth'
require 'warden/github/version'
require 'warden/github/strategy'
require 'warden/github/hook'
require 'warden/github/config'
require 'warden/github/membership_cache'
require 'warden/github/verifier'

require 'active_support/message_verifier'
require 'securerandom'
27 changes: 16 additions & 11 deletions lib/warden/github/config.rb
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,10 @@ module GitHub
#
# # This configures an additional scope that uses the github strategy
# # with custom configuration.
# config.scope_defaults :admin, :config => { :client_id => 'foobar',
# :client_secret => 'barfoo',
# :scope => 'user,repo',
# :redirect_uri => '/admin/oauth/callback' }
# config.scope_defaults :admin, config: { client_id: 'foobar',
# client_secret: 'barfoo',
# scope: 'user,repo',
# redirect_uri: '/admin/oauth/callback' }
# end
class Config
BadConfig = Class.new(StandardError)
Expand Down Expand Up @@ -88,10 +88,10 @@ def scope
end

def to_hash
{ :client_id => client_id,
:client_secret => client_secret,
:redirect_uri => redirect_uri,
:scope => scope }
{ client_id: client_id,
client_secret: client_secret,
redirect_uri: redirect_uri,
scope: scope }
end

private
Expand Down Expand Up @@ -131,16 +131,21 @@ def extract_path(uri)
end
end

def https_forwarded_proto?
env['HTTP_X_FORWARDED_PROTO'] &&
env['HTTP_X_FORWARDED_PROTO'].split(',')[0] == "https"
end

def correct_scheme(uri)
if uri.scheme != 'https' && env['HTTP_X_FORWARDED_PROTO'] == 'https'
uri.port = nil if uri.port == 80
if uri.scheme != 'https' && https_forwarded_proto?
uri.scheme = 'https'
# Reparsing will use a different URI subclass, namely URI::HTTPS which
# knows the default port for https and strips it if present.
uri = URI(uri.to_s)
end
uri.port = nil if uri.port == 80

uri
URI(uri.to_s)
end
end
end
Expand Down
7 changes: 7 additions & 0 deletions lib/warden/github/hook.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,10 @@

strategy.finalize_flow! if strategy.class == Warden::GitHub::Strategy
end

Warden::Manager.after_set_user do |user, auth, opts|
if user.is_a?(Warden::GitHub::User)
session = auth.session(opts.fetch(:scope))
user.memberships = session[:_memberships] ||= {}
end
end
14 changes: 9 additions & 5 deletions lib/warden/github/membership_cache.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,20 @@ module GitHub
# A hash subclass that acts as a cache for organization and team
# membership states. Only membership states that are true are cached. These
# are invalidated after a certain time.
class MembershipCache < ::Hash
class MembershipCache
CACHE_TIMEOUT = 60 * 5

def initialize(data)
@data = data
end

# Fetches a membership status by type and id (e.g. 'org', 'my_company')
# from cache. If no cached value is present or if the cached value
# expired, the block will be invoked and the return value, if true,
# cached for e certain time.
def fetch_membership(type, id)
type = type.to_s
id = id.to_s if id.is_a?(Symbol)
id = id.to_s

if cached_membership_valid?(type, id)
true
Expand All @@ -27,10 +31,10 @@ def fetch_membership(type, id)
private

def cached_membership_valid?(type, id)
timestamp = fetch(type).fetch(id)
timestamp = @data.fetch(type).fetch(id)

if Time.now.to_i > timestamp + CACHE_TIMEOUT
fetch(type).delete(id)
@data.fetch(type).delete(id)
false
else
true
Expand All @@ -40,7 +44,7 @@ def cached_membership_valid?(type, id)
end

def cache_membership(type, id)
hash = self[type] ||= {}
hash = @data[type] ||= {}
hash[id] = Time.now.to_i
end
end
Expand Down
14 changes: 7 additions & 7 deletions lib/warden/github/oauth.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,10 @@ def initialize(attrs={})
def authorize_uri
@authorize_uri ||= build_uri(
'/login/oauth/authorize',
:client_id => client_id,
:redirect_uri => redirect_uri,
:scope => scope,
:state => state)
client_id: client_id,
redirect_uri: redirect_uri,
scope: scope,
state: state)
end

def access_token
Expand All @@ -53,9 +53,9 @@ def load_access_token
def access_token_uri
@access_token_uri ||= build_uri(
'/login/oauth/access_token',
:client_id => client_id,
:client_secret => client_secret,
:code => code)
client_id: client_id,
client_secret: client_secret,
code: code)
end

def build_uri(path, params)
Expand Down
Loading