opensesame-github 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +4 -0
- data/.rspec +1 -0
- data/Gemfile +4 -0
- data/README.md +61 -0
- data/Rakefile +11 -0
- data/lib/opensesame/github/api.rb +41 -0
- data/lib/opensesame/github/base.rb +54 -0
- data/lib/opensesame/github/collection.rb +37 -0
- data/lib/opensesame/github/organization.rb +42 -0
- data/lib/opensesame/github/strategy.rb +34 -0
- data/lib/opensesame/github/team_member.rb +6 -0
- data/lib/opensesame/github/version.rb +5 -0
- data/lib/opensesame-github.rb +34 -0
- data/opensesame-github.gemspec +34 -0
- data/spec/opensesame/github/collection_spec.rb +35 -0
- data/spec/opensesame/github/organization_spec.rb +66 -0
- data/spec/opensesame/github/strategy_spec.rb +69 -0
- data/spec/opensesame/github/team_member_spec.rb +19 -0
- data/spec/opensesame/github_spec.rb +9 -0
- data/spec/spec_helper.rb +12 -0
- data/spec/support/omniauth.rb +18 -0
- data/spec/support/request_helpers.rb +55 -0
- data/spec/support/vcr.rb +22 -0
- data/spec/vcr/team_members.yml +65 -0
- metadata +196 -0
data/.gitignore
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
# OpenSesame
|
2
|
+
|
3
|
+
OpenSesame-Github is a [Warden](https://github.com/hassox/warden) strategy for providing "walled garden" authentication for access to Rack-based applications via Omniauth. For example, your company has internal apps and/or staging enviroments for multiple projects and you want something better than HTTP basic auth. The intent is protect the visibility of your app from the outside world.
|
4
|
+
|
5
|
+
Enter OpenSesame-Github. To authenticate, OpenSesame-Github currently uses Omniauth and the Github API to require that a user is both logged in to Github and a member of the configurable Github organization. You can use any other authentication framework or strategy behind the OpenSesame-Github to authenticate your current user.
|
6
|
+
|
7
|
+
## Usage
|
8
|
+
|
9
|
+
Register your application(s) with Github for OAuth access. For each application, you need a name, the site url,
|
10
|
+
and a callback for OAuth. The OmniAuth-Github OAuth strategy used under the hood will expect the callback at '/auth/github/callback'. So the development version of your client application might be registered as:
|
11
|
+
|
12
|
+
Name: MyApp - local
|
13
|
+
URL: http://localhost:3000
|
14
|
+
Callback URL: http://localhost:3000/auth/github/callback
|
15
|
+
|
16
|
+
In your Gemfile:
|
17
|
+
|
18
|
+
$ gem "opensesame-github"
|
19
|
+
|
20
|
+
Insert the middleware components in your Rails `config/initializers` or in your Sinatra/Rack app file:
|
21
|
+
|
22
|
+
Rails
|
23
|
+
|
24
|
+
```ruby
|
25
|
+
# Rails config/initializers/omniauth.rb
|
26
|
+
Rails.application.config.middleware.use OmniAuth::Strategies::GitHub,
|
27
|
+
GITHUB_CLIENT_ID, GITHUB_CLIENT_SECRET
|
28
|
+
|
29
|
+
Rails.application.config.middleware.use Warden::Manager do |manager|
|
30
|
+
manager.scope_defaults :team_member, :strategies => [:github_team_member]
|
31
|
+
manager.failure_app = lambda { |env| HomeController.action(:show).call(env) }
|
32
|
+
end
|
33
|
+
```
|
34
|
+
|
35
|
+
Sinatra/Rack
|
36
|
+
|
37
|
+
```ruby
|
38
|
+
# Sinatra app.rb
|
39
|
+
require 'opensesame-github'
|
40
|
+
|
41
|
+
class MyApplication < Sinatra::Base
|
42
|
+
# ...
|
43
|
+
|
44
|
+
use OmniAuth::Strategies::GitHub, GITHUB_CLIENT_ID, GITHUB_CLIENT_SECRET
|
45
|
+
|
46
|
+
use Warden::Manager do |manager|
|
47
|
+
manager.scope_defaults :team_member, :strategies => [:github_team_member]
|
48
|
+
manager.failure_app = lambda { |env| HomeController.action(:show).call(env) }
|
49
|
+
end
|
50
|
+
end
|
51
|
+
```
|
52
|
+
|
53
|
+
Configure your Github organization:
|
54
|
+
|
55
|
+
```ruby
|
56
|
+
# Rails config/initializers/omniauth.rb or Sinatra app.rb
|
57
|
+
|
58
|
+
OpenSesame::Github.configure do |c|
|
59
|
+
c.organization = 'challengepost'
|
60
|
+
end
|
61
|
+
```
|
data/Rakefile
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
require "bundler/gem_tasks"
|
3
|
+
require 'rspec/core/rake_task'
|
4
|
+
|
5
|
+
RSpec::Core::RakeTask.new do |t|
|
6
|
+
# t.pattern = "./spec/**/*_spec.rb" # default
|
7
|
+
# Put spec opts in a file named .rspec in root
|
8
|
+
end
|
9
|
+
|
10
|
+
desc "Run the specs"
|
11
|
+
task :default => ["spec"]
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'faraday'
|
3
|
+
require 'faraday_middleware'
|
4
|
+
|
5
|
+
module OpenSesame
|
6
|
+
module Github
|
7
|
+
GITHUB_API_HOST = 'https://api.github.com'
|
8
|
+
|
9
|
+
class API
|
10
|
+
|
11
|
+
def get(path = nil)
|
12
|
+
response = connection.get(path)
|
13
|
+
if response.success?
|
14
|
+
response.body
|
15
|
+
else
|
16
|
+
nil
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
protected
|
21
|
+
|
22
|
+
def connection
|
23
|
+
@connection ||= Faraday.new(url: GITHUB_API_HOST) do |conn|
|
24
|
+
conn.request :json
|
25
|
+
|
26
|
+
conn.response :json, :content_type => /\bjson|javascript$/
|
27
|
+
conn.response :logger if defined?(Rails) && !Rails.env.test?
|
28
|
+
|
29
|
+
conn.use :instrumentation if defined?(ActiveSupport) && defined?(ActiveSupport::Notifications)
|
30
|
+
conn.adapter Faraday.default_adapter
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# organization = Github::Organization.new('challengepost')
|
37
|
+
# organization.team_members
|
38
|
+
# organization.team_member?(id)
|
39
|
+
# Github::Organization.new('challengepost').team_members.find(id)
|
40
|
+
# organization.team_members.find(id)
|
41
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module OpenSesame::Github
|
4
|
+
class Base
|
5
|
+
# Public: Define readers from attributes hash
|
6
|
+
#
|
7
|
+
# symbol(s) - Method name
|
8
|
+
#
|
9
|
+
# Examples
|
10
|
+
#
|
11
|
+
# lazy_attr_reader :id, :login
|
12
|
+
#
|
13
|
+
def self.lazy_attr_reader(*attrs)
|
14
|
+
attrs.each do |attribute|
|
15
|
+
class_eval do
|
16
|
+
define_method(attribute) do
|
17
|
+
@attributes[attribute.to_s] || @attributes[attribute] # allow string or symbol access
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
attr_reader :attributes
|
24
|
+
|
25
|
+
# Public: Instantiate a new Github::TeamMember from api attributes.
|
26
|
+
#
|
27
|
+
# attributes - hash of api github team member attributes
|
28
|
+
#
|
29
|
+
# Examples
|
30
|
+
#
|
31
|
+
# Github::TeamMember.new(
|
32
|
+
# "gravatar_id"=>"f009205a899da22248cca0b772aec9c9",
|
33
|
+
# "url"=>"https://api.github.com/users/defunkt",
|
34
|
+
# "avatar_url"=>"https://secure.gravatar.com/avatar/abcd1234.png",
|
35
|
+
# "id"=>2,
|
36
|
+
# "login"=>"defunkt"
|
37
|
+
# )
|
38
|
+
# # => <Github::TeamMember>
|
39
|
+
#
|
40
|
+
# Returns new Github::TeamMember.
|
41
|
+
def initialize(attributes = {})
|
42
|
+
@attributes = attributes
|
43
|
+
yield self if block_given?
|
44
|
+
end
|
45
|
+
|
46
|
+
def ==(other)
|
47
|
+
super || (other.class == self.class && other.id == self.id)
|
48
|
+
end
|
49
|
+
|
50
|
+
def get(*args)
|
51
|
+
OpenSesame::Github.api.get(*args)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module OpenSesame::Github
|
4
|
+
class Collection < Base
|
5
|
+
include Enumerable
|
6
|
+
|
7
|
+
attr_accessor :url, :member_class
|
8
|
+
|
9
|
+
def members
|
10
|
+
@members ||= []
|
11
|
+
end
|
12
|
+
|
13
|
+
def find(id)
|
14
|
+
members.detect { |member| member.id == id }
|
15
|
+
end
|
16
|
+
|
17
|
+
def fetch
|
18
|
+
reset(get(url))
|
19
|
+
end
|
20
|
+
|
21
|
+
def reset(member_attrs)
|
22
|
+
@members = [].tap do |member_set|
|
23
|
+
member_attrs.map do |attrs|
|
24
|
+
member_set << member_class.new(attrs)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def each(&block)
|
30
|
+
members.each(&block)
|
31
|
+
end
|
32
|
+
|
33
|
+
def size
|
34
|
+
members.size
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module OpenSesame::Github
|
3
|
+
class Organization < Base
|
4
|
+
lazy_attr_reader :name
|
5
|
+
|
6
|
+
attr_writer :team_members
|
7
|
+
|
8
|
+
def team_members
|
9
|
+
@team_members ||= begin
|
10
|
+
Collection.new do |collection|
|
11
|
+
collection.member_class = TeamMember
|
12
|
+
collection.url = "/orgs/#{name}/members"
|
13
|
+
collection.fetch
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def team_member_ids
|
19
|
+
team_members.map(&:id)
|
20
|
+
end
|
21
|
+
|
22
|
+
def team_member_attributes
|
23
|
+
team_members.map(&:attributes)
|
24
|
+
end
|
25
|
+
|
26
|
+
def team_member?(team_member_id)
|
27
|
+
team_member_ids.include?(team_member_id)
|
28
|
+
end
|
29
|
+
|
30
|
+
def fetch_team_members
|
31
|
+
team_members.fetch
|
32
|
+
end
|
33
|
+
|
34
|
+
def find_team_member(team_member_id)
|
35
|
+
team_members.find(team_member_id)
|
36
|
+
end
|
37
|
+
|
38
|
+
def ==(other)
|
39
|
+
(other.class == self.class && other.name == self.name)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'warden'
|
3
|
+
require 'omniauth-github'
|
4
|
+
|
5
|
+
module OpenSesame
|
6
|
+
module Github
|
7
|
+
class Strategy < ::Warden::Strategies::Base
|
8
|
+
attr_writer :organization
|
9
|
+
|
10
|
+
def valid?
|
11
|
+
omniauth && omniauth["provider"] == "github"
|
12
|
+
end
|
13
|
+
|
14
|
+
def authenticate!
|
15
|
+
if team_member = organization.find_team_member(omniauth["uid"])
|
16
|
+
success! team_member
|
17
|
+
else
|
18
|
+
fail 'Authentication'
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def omniauth
|
23
|
+
request.env['omniauth.auth']
|
24
|
+
end
|
25
|
+
|
26
|
+
def organization
|
27
|
+
@organization ||= OpenSesame::Github.organization
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
Warden::Strategies.add(:opensesame_github, OpenSesame::Github::Strategy)
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'warden'
|
2
|
+
require 'omniauth-github'
|
3
|
+
|
4
|
+
module OpenSesame
|
5
|
+
module Github
|
6
|
+
extend self
|
7
|
+
|
8
|
+
autoload :API, 'opensesame/github/api'
|
9
|
+
autoload :Base, 'opensesame/github/base'
|
10
|
+
autoload :Collection, 'opensesame/github/collection'
|
11
|
+
autoload :Organization, 'opensesame/github/organization'
|
12
|
+
autoload :TeamMember, 'opensesame/github/team_member'
|
13
|
+
|
14
|
+
def organization_name
|
15
|
+
@@organization_name
|
16
|
+
end
|
17
|
+
|
18
|
+
def organization_name=(organization_name)
|
19
|
+
@@organization_name = organization_name
|
20
|
+
end
|
21
|
+
|
22
|
+
def organization
|
23
|
+
Organization.new(:name => organization_name)
|
24
|
+
end
|
25
|
+
|
26
|
+
def api
|
27
|
+
@@api ||= API.new
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
require 'opensesame/github/version'
|
34
|
+
require 'opensesame/github/strategy'
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "opensesame/github/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "opensesame-github"
|
7
|
+
s.version = OpenSesame::Github::VERSION
|
8
|
+
s.authors = ["Ross Kaffenberger"]
|
9
|
+
s.email = ["rosskaff@gmail.com"]
|
10
|
+
s.homepage = ""
|
11
|
+
s.summary = %q{Walled-garden authentication for your github organization}
|
12
|
+
s.description = %q{Provide walled-garden authentication to public members of
|
13
|
+
your github organization for your rack-based apps with warden and omniauth-github}
|
14
|
+
|
15
|
+
s.rubyforge_project = "opensesame-github"
|
16
|
+
|
17
|
+
s.files = `git ls-files`.split("\n")
|
18
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
19
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
20
|
+
s.require_paths = ["lib"]
|
21
|
+
|
22
|
+
# specify any dependencies here; for example:
|
23
|
+
s.add_dependency 'warden'
|
24
|
+
s.add_dependency 'omniauth-github'
|
25
|
+
s.add_dependency 'faraday', '0.8.0.rc2'
|
26
|
+
s.add_dependency 'faraday_middleware'
|
27
|
+
|
28
|
+
s.add_development_dependency "rspec", "~> 2.8.0"
|
29
|
+
s.add_development_dependency "vcr"
|
30
|
+
s.add_development_dependency "fakeweb"
|
31
|
+
s.add_development_dependency "pry"
|
32
|
+
s.add_development_dependency "pry-nav"
|
33
|
+
s.add_development_dependency "rake"
|
34
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
describe OpenSesame::Github::Collection do
|
5
|
+
|
6
|
+
let(:collection) {
|
7
|
+
OpenSesame::Github::Collection.new do |coll|
|
8
|
+
coll.member_class = OpenSesame::Github::TeamMember
|
9
|
+
end
|
10
|
+
}
|
11
|
+
|
12
|
+
before do
|
13
|
+
@team_member_attributes = [
|
14
|
+
{"id" => 2, "login" => "defunkt" },
|
15
|
+
{"id" => 3, "login" => "mojombo" }
|
16
|
+
]
|
17
|
+
collection.reset(@team_member_attributes)
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should instantiate team members from given attributes" do
|
21
|
+
collection.first.should be_a(OpenSesame::Github::TeamMember)
|
22
|
+
collection.size.should == 2
|
23
|
+
end
|
24
|
+
|
25
|
+
describe "find" do
|
26
|
+
it "should be able to find an existing id with valid id" do
|
27
|
+
collection.find(2).should == OpenSesame::Github::TeamMember.new("id" => 2, "login" => "defunkt")
|
28
|
+
end
|
29
|
+
|
30
|
+
it "returns nil if no member with given id" do
|
31
|
+
collection.find(1000).should be_nil
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
describe OpenSesame::Github::Organization do
|
5
|
+
|
6
|
+
let(:organization) { OpenSesame::Github::Organization.new(:name => 'challengepost') }
|
7
|
+
|
8
|
+
|
9
|
+
it "should initialize with organization name" do
|
10
|
+
organization.name.should == 'challengepost'
|
11
|
+
end
|
12
|
+
|
13
|
+
context "team_members stubbed" do
|
14
|
+
let(:team_members) { OpenSesame::Github::Collection.new { |c| c.member_class = OpenSesame::Github::TeamMember } }
|
15
|
+
|
16
|
+
before do
|
17
|
+
@attribute_set = [ { "id" => 1 }, { "id" => 2 } ]
|
18
|
+
team_members.stub!(:refresh)
|
19
|
+
team_members.reset(@attribute_set)
|
20
|
+
organization.team_members = team_members
|
21
|
+
end
|
22
|
+
|
23
|
+
it { organization.team_member_ids.should == [1, 2] }
|
24
|
+
it { organization.team_member_attributes.should == @attribute_set }
|
25
|
+
|
26
|
+
describe "team_member?" do
|
27
|
+
it "is true if has team member with given team member id" do
|
28
|
+
organization.team_member?(1).should be_true
|
29
|
+
end
|
30
|
+
|
31
|
+
it "is true if has team member with given team member id" do
|
32
|
+
organization.team_member?(-1).should be_false
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
it "fetch_team_members" do
|
37
|
+
team_members.should_receive(:fetch)
|
38
|
+
organization.fetch_team_members
|
39
|
+
end
|
40
|
+
|
41
|
+
it "find_team_member" do
|
42
|
+
team_members.should_receive(:find).with(1)
|
43
|
+
organization.find_team_member(1)
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
context "team_members via api" do
|
49
|
+
describe "team_members", :vcr, :record => :new_episodes, :cassette => 'team_members' do
|
50
|
+
it "should fetch team_members via api" do
|
51
|
+
organization.team_members.should be_a(OpenSesame::Github::Collection)
|
52
|
+
organization.team_members.first.should be_a(OpenSesame::Github::TeamMember)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
describe "==" do
|
58
|
+
it "equal for same name" do
|
59
|
+
OpenSesame::Github::Organization.new(:name => "apple") == OpenSesame::Github::Organization.new(:name => "apple")
|
60
|
+
end
|
61
|
+
|
62
|
+
it "not equal for different name" do
|
63
|
+
OpenSesame::Github::Organization.new(:name => "apple") == OpenSesame::Github::Organization.new(:name => "microsoft")
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
describe OpenSesame::Github::Strategy do
|
5
|
+
|
6
|
+
let(:strategy) { OpenSesame::Github::Strategy.new(@env) }
|
7
|
+
|
8
|
+
before do
|
9
|
+
@env = env_with_params
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should be a warden strategy" do
|
13
|
+
OpenSesame::Github::Strategy.ancestors.should include(Warden::Strategies::Base)
|
14
|
+
end
|
15
|
+
|
16
|
+
it "is valid when github is provider in request env omniauth key" do
|
17
|
+
@env['omniauth.auth'] = { "provider" => "github" }
|
18
|
+
strategy.should be_valid
|
19
|
+
end
|
20
|
+
|
21
|
+
it "is not valid when provider is other in request env omniauth key" do
|
22
|
+
@env['omniauth.auth'] = { "provider" => "another" }
|
23
|
+
strategy.should_not be_valid
|
24
|
+
end
|
25
|
+
|
26
|
+
it "is not valid when omniauth key is missing in request env" do
|
27
|
+
strategy.should_not be_valid
|
28
|
+
end
|
29
|
+
|
30
|
+
it "can have a scope" do
|
31
|
+
strategy = OpenSesame::Github::Strategy.new(@env, :team_member)
|
32
|
+
strategy.scope.should == :team_member
|
33
|
+
end
|
34
|
+
|
35
|
+
describe "authenticate!" do
|
36
|
+
let(:organization) { OpenSesame::Github::Organization.new }
|
37
|
+
let(:team_members) { OpenSesame::Github::Collection.new }
|
38
|
+
|
39
|
+
before do
|
40
|
+
@env['omniauth.auth'] = { "provider" => "github", "uid" => 123 }
|
41
|
+
|
42
|
+
team_members.stub!(:find => nil)
|
43
|
+
organization.team_members = team_members
|
44
|
+
strategy.organization = organization
|
45
|
+
end
|
46
|
+
|
47
|
+
it "success" do
|
48
|
+
team_members.should_receive(:find).with(123).and_return(:team_member)
|
49
|
+
strategy._run!
|
50
|
+
strategy.user.should == :team_member
|
51
|
+
strategy.result.should == :success
|
52
|
+
end
|
53
|
+
|
54
|
+
it "fail" do
|
55
|
+
team_members.should_receive(:find).with(123).and_return(nil)
|
56
|
+
strategy._run!
|
57
|
+
strategy.user.should be_nil
|
58
|
+
strategy.result.should == :failure
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
describe "organization" do
|
63
|
+
it "should initialize based on configuration" do
|
64
|
+
OpenSesame::Github.organization_name = 'apple'
|
65
|
+
strategy.organization.should == OpenSesame::Github::Organization.new(:name => 'apple')
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
describe OpenSesame::Github::TeamMember do
|
5
|
+
|
6
|
+
describe "==" do
|
7
|
+
it "is true based on identity" do
|
8
|
+
OpenSesame::Github::TeamMember.new("id" => 2).should == OpenSesame::Github::TeamMember.new("id" => 2)
|
9
|
+
end
|
10
|
+
|
11
|
+
it "is false with mismatched ids" do
|
12
|
+
OpenSesame::Github::TeamMember.new("id" => 2).should_not == OpenSesame::Github::TeamMember.new("id" => 3)
|
13
|
+
end
|
14
|
+
|
15
|
+
it "is false with mismatched classes" do
|
16
|
+
OpenSesame::Github::TeamMember.new("id" => 2).should_not == OpenSesame::Github::Organization.new("id" => 2)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'bundler/setup'
|
2
|
+
require 'rspec'
|
3
|
+
require 'opensesame-github'
|
4
|
+
|
5
|
+
Dir[File.expand_path('../support/**/*', __FILE__)].each { |f| require f }
|
6
|
+
|
7
|
+
RSpec.configure do |config|
|
8
|
+
|
9
|
+
config.after(:each) do
|
10
|
+
OpenSesame::Github.organization_name = nil
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# OmniAuth.config.test_mode = true
|
2
|
+
|
3
|
+
# module OmniauthHelpers
|
4
|
+
# def setup_for_github_login(user)
|
5
|
+
# OmniAuth.config.mock_auth[:github] = {
|
6
|
+
# "provider" => 'github',
|
7
|
+
# "uid" => user.id
|
8
|
+
# }
|
9
|
+
# end
|
10
|
+
|
11
|
+
# def login_as(user)
|
12
|
+
# setup_for_github_login user
|
13
|
+
# visit root_path
|
14
|
+
# click_link 'login with github'
|
15
|
+
# end
|
16
|
+
# end
|
17
|
+
|
18
|
+
# RSpec.configuration.send :include, OmniauthHelpers
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
# courtesy of hassox/warden
|
4
|
+
require 'rack'
|
5
|
+
|
6
|
+
module RequestHelpers
|
7
|
+
FAILURE_APP = lambda{|e|[401, {"Content-Type" => "text/plain"}, ["You Fail!"]] }
|
8
|
+
|
9
|
+
def env_with_params(path = "/", params = {}, env = {})
|
10
|
+
method = params.delete(:method) || "GET"
|
11
|
+
env = { 'HTTP_VERSION' => '1.1', 'REQUEST_METHOD' => "#{method}" }.merge(env)
|
12
|
+
Rack::MockRequest.env_for("#{path}?#{Rack::Utils.build_query(params)}", env)
|
13
|
+
end
|
14
|
+
|
15
|
+
def setup_rack(app = nil, opts = {}, &block)
|
16
|
+
app ||= block if block_given?
|
17
|
+
|
18
|
+
opts[:failure_app] ||= failure_app
|
19
|
+
opts[:default_strategies] ||= [:password]
|
20
|
+
opts[:default_serializers] ||= [:session]
|
21
|
+
blk = opts[:configurator] || proc{}
|
22
|
+
|
23
|
+
Rack::Builder.new do
|
24
|
+
use opts[:session] || Warden::Spec::Helpers::Session
|
25
|
+
use Warden::Manager, opts, &blk
|
26
|
+
run app
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def valid_response
|
31
|
+
Rack::Response.new("OK").finish
|
32
|
+
end
|
33
|
+
|
34
|
+
def failure_app
|
35
|
+
Warden::Spec::Helpers::FAILURE_APP
|
36
|
+
end
|
37
|
+
|
38
|
+
def success_app
|
39
|
+
lambda{|e| [200, {"Content-Type" => "text/plain"}, ["You Win"]]}
|
40
|
+
end
|
41
|
+
|
42
|
+
class Session
|
43
|
+
attr_accessor :app
|
44
|
+
def initialize(app,configs = {})
|
45
|
+
@app = app
|
46
|
+
end
|
47
|
+
|
48
|
+
def call(e)
|
49
|
+
e['rack.session'] ||= {}
|
50
|
+
@app.call(e)
|
51
|
+
end
|
52
|
+
end # session
|
53
|
+
end
|
54
|
+
|
55
|
+
RSpec.configuration.send(:include, RequestHelpers)
|
data/spec/support/vcr.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'vcr'
|
3
|
+
require 'fakeweb'
|
4
|
+
|
5
|
+
VCR.configure do |c|
|
6
|
+
c.cassette_library_dir = 'spec/vcr'
|
7
|
+
c.allow_http_connections_when_no_cassette = true
|
8
|
+
c.hook_into :fakeweb
|
9
|
+
end
|
10
|
+
|
11
|
+
RSpec.configure do |c|
|
12
|
+
c.treat_symbols_as_metadata_keys_with_true_values = true
|
13
|
+
c.around(:each, :vcr) do |example|
|
14
|
+
name = example.metadata[:cassette]
|
15
|
+
unless name
|
16
|
+
namespace = example.metadata[:full_description].split.first.split("::").last.downcase
|
17
|
+
spec_name = example.metadata[:description].split.join("_")
|
18
|
+
name = [namespace, spec_name].join("/")
|
19
|
+
end
|
20
|
+
VCR.use_cassette(name, :record => example.metadata[:record]) { example.call }
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
---
|
2
|
+
http_interactions:
|
3
|
+
- request:
|
4
|
+
method: get
|
5
|
+
uri: https://api.github.com/orgs/challengepost/members
|
6
|
+
body:
|
7
|
+
encoding: US-ASCII
|
8
|
+
string: ''
|
9
|
+
headers:
|
10
|
+
accept-encoding:
|
11
|
+
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
|
12
|
+
accept:
|
13
|
+
- ! '*/*'
|
14
|
+
user-agent:
|
15
|
+
- Ruby
|
16
|
+
connection:
|
17
|
+
- close
|
18
|
+
response:
|
19
|
+
status:
|
20
|
+
code: 200
|
21
|
+
message: OK
|
22
|
+
headers:
|
23
|
+
server:
|
24
|
+
- nginx/1.0.13
|
25
|
+
date:
|
26
|
+
- Mon, 26 Mar 2012 21:45:32 GMT
|
27
|
+
content-type:
|
28
|
+
- application/json; charset=utf-8
|
29
|
+
transfer-encoding:
|
30
|
+
- chunked
|
31
|
+
connection:
|
32
|
+
- close
|
33
|
+
status:
|
34
|
+
- 200 OK
|
35
|
+
x-ratelimit-limit:
|
36
|
+
- '5000'
|
37
|
+
etag:
|
38
|
+
- ! '"1c8e46953df6f011d11144e376a72ad4"'
|
39
|
+
x-ratelimit-remaining:
|
40
|
+
- '4997'
|
41
|
+
content-encoding:
|
42
|
+
- gzip
|
43
|
+
body:
|
44
|
+
encoding: ASCII-8BIT
|
45
|
+
string: !binary |-
|
46
|
+
H4sIAAAAAAAAA7XXy4rUUBAG4HdpcDd2V9W5CyK4cOMjiMi51OnJmE4PuQiD
|
47
|
+
+O6eHme6o1kkBrJoyCJJ1f9ROVR/+bk7tv6H7337rUq7d7sM4AiUt84lT0TS
|
48
|
+
xughGEOeo4tud7cb2rrceN/3j927w8E/Vvtj1d8PYR/Pp8PQcdsdwnfuuprb
|
49
|
+
cvfLy/9+qOM4tLx/Lf385J8bD3MNfEjvr6VLd3ve++/+5Kt9w/3Bdx333aif
|
50
|
+
N/SpOvkjd+Xitdr4+i1K2D82x9LoJT4qIYyku119PlZNSXkN8uvuXymbQ7DZ
|
51
|
+
qWiFS8nkmLyW0sqAIgedaKnUueZuhdNc+Y2dCAyasdNzjKmSit44djYo65Ci
|
52
|
+
lhFI+ZApEiV0uEwpnuv0MNRPK5zmGtjUSYNResR0zTGFEsAuOOEck1KQfbYS
|
53
|
+
WAUmLJ9itHIZ1P25rp/wMnv/+93N1d/USVoyAm7j9BpjykSJIAGnqBxGw1KR
|
54
|
+
LB8fE6N3GJxexvQQT0O97nyaa2BTJwKrYOR0zTGFSmCN4khojIHEyednJw3Z
|
55
|
+
CqOEWgjV+rquunOzYqLmOthWCgXp20A9XHNMpVhYEJYU6EwiaxCsKAdbDnan
|
56
|
+
gT0vk/rMP6rm47k5+rZfgTXXxKZYqKQej9VfWaZgEXJZEDwGjEp6maTBACEI
|
57
|
+
G7JInM0ysJNvm6fuVFaHFVxzLWzKpZ1zRt6Ga5RkikXOSTRSeNDl1LI+orOc
|
58
|
+
bSw/tsxhIVaVhhVMc8U3ZUJbNqPRYXW6ZJgCJSlSFFoaGRJ4UsTJgUlSK8Ry
|
59
|
+
bi2cpqYaypq3gmiu/KZE5TzXRLdJekkxRWJEc1mkgCnIEGUQUstybIXELmmI
|
60
|
+
y6ao5X5om74d1kDNtbAplHICzQhqlGSKFQC188Zmq9Dp8m/GJi3KYu8ToDRp
|
61
|
+
4Y7Qnruu9ysmaq78plCI2ojbQL2EmBpFjzmgVEahypf9PKMGx4wKfCK/cD3o
|
62
|
+
hgQNnlYgzdXfFkkYZ0dKrzF+ff0NaaJBrxAPAAA=
|
63
|
+
http_version: '1.1'
|
64
|
+
recorded_at: Mon, 26 Mar 2012 21:45:32 GMT
|
65
|
+
recorded_with: VCR 2.0.0
|
metadata
ADDED
@@ -0,0 +1,196 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: opensesame-github
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Ross Kaffenberger
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-03-26 00:00:00.000000000Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: warden
|
16
|
+
requirement: &70104920804440 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *70104920804440
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: omniauth-github
|
27
|
+
requirement: &70104920803200 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ! '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
33
|
+
type: :runtime
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *70104920803200
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: faraday
|
38
|
+
requirement: &70104920800760 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - =
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: 0.8.0.rc2
|
44
|
+
type: :runtime
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: *70104920800760
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: faraday_middleware
|
49
|
+
requirement: &70104920799600 !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
type: :runtime
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: *70104920799600
|
58
|
+
- !ruby/object:Gem::Dependency
|
59
|
+
name: rspec
|
60
|
+
requirement: &70104920798400 !ruby/object:Gem::Requirement
|
61
|
+
none: false
|
62
|
+
requirements:
|
63
|
+
- - ~>
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: 2.8.0
|
66
|
+
type: :development
|
67
|
+
prerelease: false
|
68
|
+
version_requirements: *70104920798400
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: vcr
|
71
|
+
requirement: &70104920797240 !ruby/object:Gem::Requirement
|
72
|
+
none: false
|
73
|
+
requirements:
|
74
|
+
- - ! '>='
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '0'
|
77
|
+
type: :development
|
78
|
+
prerelease: false
|
79
|
+
version_requirements: *70104920797240
|
80
|
+
- !ruby/object:Gem::Dependency
|
81
|
+
name: fakeweb
|
82
|
+
requirement: &70104920796100 !ruby/object:Gem::Requirement
|
83
|
+
none: false
|
84
|
+
requirements:
|
85
|
+
- - ! '>='
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: '0'
|
88
|
+
type: :development
|
89
|
+
prerelease: false
|
90
|
+
version_requirements: *70104920796100
|
91
|
+
- !ruby/object:Gem::Dependency
|
92
|
+
name: pry
|
93
|
+
requirement: &70104920795080 !ruby/object:Gem::Requirement
|
94
|
+
none: false
|
95
|
+
requirements:
|
96
|
+
- - ! '>='
|
97
|
+
- !ruby/object:Gem::Version
|
98
|
+
version: '0'
|
99
|
+
type: :development
|
100
|
+
prerelease: false
|
101
|
+
version_requirements: *70104920795080
|
102
|
+
- !ruby/object:Gem::Dependency
|
103
|
+
name: pry-nav
|
104
|
+
requirement: &70104920783200 !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ! '>='
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
110
|
+
type: :development
|
111
|
+
prerelease: false
|
112
|
+
version_requirements: *70104920783200
|
113
|
+
- !ruby/object:Gem::Dependency
|
114
|
+
name: rake
|
115
|
+
requirement: &70104920781740 !ruby/object:Gem::Requirement
|
116
|
+
none: false
|
117
|
+
requirements:
|
118
|
+
- - ! '>='
|
119
|
+
- !ruby/object:Gem::Version
|
120
|
+
version: '0'
|
121
|
+
type: :development
|
122
|
+
prerelease: false
|
123
|
+
version_requirements: *70104920781740
|
124
|
+
description: ! "Provide walled-garden authentication to public members of\n your
|
125
|
+
github organization for your rack-based apps with warden and omniauth-github"
|
126
|
+
email:
|
127
|
+
- rosskaff@gmail.com
|
128
|
+
executables: []
|
129
|
+
extensions: []
|
130
|
+
extra_rdoc_files: []
|
131
|
+
files:
|
132
|
+
- .gitignore
|
133
|
+
- .rspec
|
134
|
+
- Gemfile
|
135
|
+
- README.md
|
136
|
+
- Rakefile
|
137
|
+
- lib/opensesame-github.rb
|
138
|
+
- lib/opensesame/github/api.rb
|
139
|
+
- lib/opensesame/github/base.rb
|
140
|
+
- lib/opensesame/github/collection.rb
|
141
|
+
- lib/opensesame/github/organization.rb
|
142
|
+
- lib/opensesame/github/strategy.rb
|
143
|
+
- lib/opensesame/github/team_member.rb
|
144
|
+
- lib/opensesame/github/version.rb
|
145
|
+
- opensesame-github.gemspec
|
146
|
+
- spec/opensesame/github/collection_spec.rb
|
147
|
+
- spec/opensesame/github/organization_spec.rb
|
148
|
+
- spec/opensesame/github/strategy_spec.rb
|
149
|
+
- spec/opensesame/github/team_member_spec.rb
|
150
|
+
- spec/opensesame/github_spec.rb
|
151
|
+
- spec/spec_helper.rb
|
152
|
+
- spec/support/omniauth.rb
|
153
|
+
- spec/support/request_helpers.rb
|
154
|
+
- spec/support/vcr.rb
|
155
|
+
- spec/vcr/team_members.yml
|
156
|
+
homepage: ''
|
157
|
+
licenses: []
|
158
|
+
post_install_message:
|
159
|
+
rdoc_options: []
|
160
|
+
require_paths:
|
161
|
+
- lib
|
162
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
163
|
+
none: false
|
164
|
+
requirements:
|
165
|
+
- - ! '>='
|
166
|
+
- !ruby/object:Gem::Version
|
167
|
+
version: '0'
|
168
|
+
segments:
|
169
|
+
- 0
|
170
|
+
hash: 4431237478611906206
|
171
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
172
|
+
none: false
|
173
|
+
requirements:
|
174
|
+
- - ! '>='
|
175
|
+
- !ruby/object:Gem::Version
|
176
|
+
version: '0'
|
177
|
+
segments:
|
178
|
+
- 0
|
179
|
+
hash: 4431237478611906206
|
180
|
+
requirements: []
|
181
|
+
rubyforge_project: opensesame-github
|
182
|
+
rubygems_version: 1.8.10
|
183
|
+
signing_key:
|
184
|
+
specification_version: 3
|
185
|
+
summary: Walled-garden authentication for your github organization
|
186
|
+
test_files:
|
187
|
+
- spec/opensesame/github/collection_spec.rb
|
188
|
+
- spec/opensesame/github/organization_spec.rb
|
189
|
+
- spec/opensesame/github/strategy_spec.rb
|
190
|
+
- spec/opensesame/github/team_member_spec.rb
|
191
|
+
- spec/opensesame/github_spec.rb
|
192
|
+
- spec/spec_helper.rb
|
193
|
+
- spec/support/omniauth.rb
|
194
|
+
- spec/support/request_helpers.rb
|
195
|
+
- spec/support/vcr.rb
|
196
|
+
- spec/vcr/team_members.yml
|