bunto-auth 2.1.0

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.
@@ -0,0 +1,42 @@
1
+ class BuntoAuth
2
+ class AuthSite < Sinatra::Base
3
+ configure :production do
4
+ require "rack-ssl-enforcer"
5
+ use Rack::SslEnforcer if BuntoAuth.ssl?
6
+ end
7
+
8
+ use Rack::Session::Cookie, :http_only => true,
9
+ :secret => ENV["SESSION_SECRET"] || SecureRandom.hex
10
+
11
+ set :github_options, :scopes => "read:org"
12
+
13
+ ENV["WARDEN_GITHUB_VERIFIER_SECRET"] ||= SecureRandom.hex
14
+ register Sinatra::Auth::Github
15
+
16
+ use Rack::Logger
17
+
18
+ include BuntoAuth::Helpers
19
+
20
+ before do
21
+ pass if whitelisted?
22
+
23
+ logger.info "Authentication strategy: #{authentication_strategy}"
24
+
25
+ case authentication_strategy
26
+ when :team
27
+ github_team_authenticate! ENV["GITHUB_TEAM_ID"]
28
+ when :teams
29
+ github_teams_authenticate! ENV["GITHUB_TEAM_IDS"].split(",")
30
+ when :org
31
+ github_organization_authenticate! ENV["GITHUB_ORG_NAME"]
32
+ else
33
+ raise BuntoAuth::ConfigError
34
+ end
35
+ end
36
+
37
+ get "/logout" do
38
+ logout!
39
+ redirect "/"
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,13 @@
1
+ class BuntoAuth
2
+ class BuntoSite < Sinatra::Base
3
+ register Sinatra::Index
4
+ set :public_folder, File.expand_path("_site", Dir.pwd)
5
+ use_static_index "index.html"
6
+
7
+ not_found do
8
+ status 404
9
+ four_oh_four = File.expand_path("_site/404.html", Dir.pwd)
10
+ File.read(four_oh_four) if File.exist?(four_oh_four)
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,72 @@
1
+ class BuntoAuth
2
+ class Commands
3
+ FILES = %w(Rakefile config.ru .gitignore .env).freeze
4
+ VARS = %w(client_id client_secret team_id org_name).freeze
5
+
6
+ def self.source
7
+ @source ||= File.expand_path("../../templates", File.dirname(__FILE__))
8
+ end
9
+
10
+ def self.destination
11
+ @destination ||= Dir.pwd
12
+ end
13
+
14
+ def self.changed?
15
+ !execute_command("git", "status", destination, "--porcelain").empty?
16
+ rescue
17
+ false
18
+ end
19
+
20
+ def self.execute_command(*args)
21
+ output, status = Open3.capture2e(*args)
22
+ raise "Command `#{args.join(" ")}` failed: #{output}" unless status.exitstatus.zero?
23
+ output
24
+ end
25
+
26
+ def self.copy_templates
27
+ FILES.each do |file|
28
+ if File.exist? "#{destination}/#{file}"
29
+ puts "* #{destination}/#{file} already exists... skipping."
30
+ else
31
+ puts "* creating #{destination}/#{file}"
32
+ FileUtils.cp "#{source}/#{file}", "#{destination}/#{file}"
33
+ end
34
+ end
35
+ end
36
+
37
+ def self.team_id(org, team)
38
+ client = Octokit::Client.new :access_token => ENV["GITHUB_TOKEN"]
39
+ client.auto_paginate = true
40
+ teams = client.organization_teams org
41
+ found = teams.find { |t| t[:slug] == team }
42
+ found[:id] if found
43
+ end
44
+
45
+ def self.env_var_set?(var)
46
+ !ENV[var].to_s.blank?
47
+ end
48
+
49
+ def self.init_repo
50
+ execute_command "git", "init", destination
51
+ FILES.each do |file|
52
+ next if file == ".env"
53
+ execute_command("git", "add", "--", "#{destination}/#{file}")
54
+ end
55
+ end
56
+
57
+ def self.initial_commit
58
+ execute_command "git", "commit", "-m", "'[Bunto Auth] Initial setup'"
59
+ end
60
+
61
+ def self.heroku_remote_set?
62
+ remotes = execute_command "git", "remote", "-v"
63
+ !!(remotes =~ %r!^heroku\s!)
64
+ end
65
+
66
+ def self.configure_heroku(options)
67
+ VARS.each do |var|
68
+ execute_command "heroku", "config:set", "GITHUB_#{var.upcase}=#{options[var]}" if options[var]
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,23 @@
1
+ class BuntoAuth
2
+ def self.config_file
3
+ File.join(Dir.pwd, "_config.yml")
4
+ end
5
+
6
+ def self.config
7
+ @config ||= begin
8
+ config = YAML.safe_load_file(config_file)
9
+ config["bunto_auth"] || {}
10
+ rescue
11
+ {}
12
+ end
13
+ end
14
+
15
+ def self.whitelist
16
+ whitelist = BuntoAuth.config["whitelist"]
17
+ Regexp.new(whitelist.join("|")) unless whitelist.nil?
18
+ end
19
+
20
+ def self.ssl?
21
+ !!BuntoAuth.config["ssl"]
22
+ end
23
+ end
@@ -0,0 +1,7 @@
1
+ class BuntoAuth
2
+ class ConfigError < RuntimeError
3
+ def message
4
+ "Bunto Auth is refusing to serve your site because your oauth credentials are not properly configured."
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,18 @@
1
+ class BuntoAuth
2
+ module Helpers
3
+ def whitelisted?
4
+ return true if request.path_info == "/logout"
5
+ !!(BuntoAuth.whitelist && BuntoAuth.whitelist.match(request.path_info))
6
+ end
7
+
8
+ def authentication_strategy
9
+ if !ENV["GITHUB_TEAM_ID"].to_s.blank?
10
+ :team
11
+ elsif !ENV["GITHUB_TEAM_IDS"].to_s.blank?
12
+ :teams
13
+ elsif !ENV["GITHUB_ORG_NAME"].to_s.blank?
14
+ :org
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,13 @@
1
+ module Sinatra
2
+ module Auth
3
+ module Github
4
+ module Helpers
5
+ # Like the native github_team_authenticate! but accepts an array of team ids
6
+ def github_teams_authenticate!(teams)
7
+ authenticate!
8
+ halt([401, "Unauthorized User"]) unless teams.any? { |team_id| github_team_access?(team_id) }
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,3 @@
1
+ class BuntoAuth
2
+ VERSION = "2.1.0".freeze
3
+ end
@@ -0,0 +1,7 @@
1
+ #!/bin/sh
2
+
3
+ set -e
4
+
5
+ echo "Let's get set up here..."
6
+ bundle install
7
+ echo "Boom."
@@ -0,0 +1,13 @@
1
+ #!/bin/sh
2
+ # Test that all dependencies resolve, and that the thing actually fires
3
+
4
+ set -e
5
+
6
+ export GITHUB_CLIENT_ID=FOO
7
+ export GITHUB_CLIENT_SECRET=BAR
8
+ export GITHUB_ORG_NAME="bunto"
9
+
10
+ bundle exec rake spec
11
+ bundle exec rubocop
12
+ bundle exec gem build bunto-auth.gemspec
13
+ bundle exec bunto-auth --version
@@ -0,0 +1 @@
1
+ bundle exec pry -r "./lib/bunto-auth"
@@ -0,0 +1,38 @@
1
+ #!/bin/sh
2
+ # Tag and push a release.
3
+
4
+ set -e
5
+
6
+ # Make sure we're in the project root.
7
+
8
+ cd $(dirname "$0")/..
9
+
10
+ # Build a new gem archive.
11
+
12
+ rm -rf bunto-auth-*.gem
13
+ gem build -q bunto-auth.gemspec
14
+
15
+ # Make sure we're on the master branch.
16
+
17
+ (git branch | grep -q '* master') || {
18
+ echo "Only release from the master branch."
19
+ exit 1
20
+ }
21
+
22
+ # Figure out what version we're releasing.
23
+
24
+ tag=v`ls bunto-auth-*.gem | sed 's/^bunto-auth-\(.*\)\.gem$/\1/'`
25
+
26
+ # Make sure we haven't released this version before.
27
+
28
+ git fetch -t origin
29
+
30
+ (git tag -l | grep -q "$tag") && {
31
+ echo "Whoops, there's already a '${tag}' tag."
32
+ exit 1
33
+ }
34
+
35
+ # Tag it and bag it.
36
+
37
+ gem push bunto-auth-*.gem && git tag "$tag" &&
38
+ git push origin master && git push origin "$tag"
@@ -0,0 +1,3 @@
1
+ #! /bin/sh
2
+
3
+ bundle exec rake site
@@ -0,0 +1,5 @@
1
+ #!/bin/sh
2
+
3
+ set -e
4
+
5
+ bundle exec bunto-auth setup
@@ -0,0 +1,74 @@
1
+ require "spec_helper"
2
+
3
+ describe "logged in user" do
4
+ include Rack::Test::Methods
5
+
6
+ def app
7
+ BuntoAuth.site
8
+ end
9
+
10
+ before(:each) do
11
+ setup_tmp_dir
12
+ @user = make_user("login" => "buntotest")
13
+ login_as @user
14
+
15
+ ENV["GITHUB_ORG_NAME"] = "balter-test-org"
16
+
17
+ stub_request(:get, "https://api.github.com/orgs/#{ENV["GITHUB_ORG_NAME"]}/members/buntotest")
18
+ .to_return(:status => 200)
19
+ end
20
+
21
+ it "shows the securocat when github returns an oauth error" do
22
+ get "/auth/github/callback?error=redirect_uri_mismatch"
23
+ expect(last_response.body).to match(%r!securocat\.png!)
24
+ end
25
+
26
+ it "logs the user out" do
27
+ get "/logout"
28
+ expect(last_response.status).to eql(302)
29
+ expect(last_response.headers["Location"]).to eql("http://example.org/")
30
+
31
+ get "/"
32
+ expect(last_response.status).to eql(302)
33
+ expect(last_response.headers["Location"]).to match(%r!^https://github\.com/login/oauth/authorize!)
34
+ end
35
+ end
36
+
37
+ describe "logged out user" do
38
+ include Rack::Test::Methods
39
+
40
+ def app
41
+ BuntoAuth.site
42
+ end
43
+
44
+ before do
45
+ ENV["GITHUB_ORG_NAME"] = "balter-test-org"
46
+ end
47
+
48
+ it "doesn't let you view indexes" do
49
+ get "/"
50
+ expect(last_response.status).to eql(302)
51
+ expect(last_response.headers["Location"]).to match(%r!^https://github\.com/login/oauth/authorize!)
52
+
53
+ get "/some_dir"
54
+ expect(last_response.status).to eql(302)
55
+ expect(last_response.headers["Location"]).to match(%r!^https://github\.com/login/oauth/authorize!)
56
+ end
57
+
58
+ it "doesn't let you view files" do
59
+ get "/index.html"
60
+ expect(last_response.status).to eql(302)
61
+ expect(last_response.headers["Location"]).to match(%r!^https://github\.com/login/oauth/authorize!)
62
+
63
+ get "/some_dir/index.html"
64
+ expect(last_response.status).to eql(302)
65
+ expect(last_response.headers["Location"]).to match(%r!^https://github\.com/login/oauth/authorize!)
66
+ end
67
+
68
+ it "refuses to serve the site without an authentication strategy" do
69
+ ENV["GITHUB_ORG_NAME"] = nil
70
+ ENV["GITHUB_TEAM_ID"] = nil
71
+ ENV["GITHUB_TEAMS_ID"] = nil
72
+ expect { get "/" }.to raise_error(BuntoAuth::ConfigError)
73
+ end
74
+ end
@@ -0,0 +1,43 @@
1
+ require "spec_helper"
2
+
3
+ describe "bin" do
4
+ before(:each) do
5
+ setup_tmp_dir
6
+ end
7
+
8
+ it "spits out the help do" do
9
+ env = { "GITHUB_TOKEN" => nil }
10
+ output = execute_bin(env, "--help")
11
+ expect(output).to match(%r!A simple way to use Github OAuth to serve a protected bunto site to your GitHub organization!)
12
+ end
13
+
14
+ describe "team id" do
15
+ it "errors if no token is given" do
16
+ env = { "GITHUB_TOKEN" => nil }
17
+ expect { execute_bin(env, "team_id", "--org", "balter-test-org", "--team", "1") }.to raise_error(RuntimeError)
18
+ .with_message(%r!prefix the bunto-auth command with GITHUB_TOKEN!)
19
+ end
20
+
21
+ it "errors if no team_id or org_name is given" do
22
+ env = { "GITHUB_TOKEN" => "1234" }
23
+ expect { execute_bin(env, "team_id") }.to raise_error(RuntimeError)
24
+ .with_message(%r!An org name and team ID are required!)
25
+ end
26
+ end
27
+
28
+ it "initializes a new site" do
29
+ `git init`
30
+ `git add .`
31
+ `git commit -m 'initial commit'`
32
+ execute_bin({ "RACK_ENV" => "TEST" }, "new")
33
+ expect(File).to exist("#{tmp_dir}/config.ru")
34
+ expect(File).to exist("#{tmp_dir}/Rakefile")
35
+ expect(File).to exist("#{tmp_dir}/.gitignore")
36
+ expect(File).to exist("#{tmp_dir}/.env")
37
+ end
38
+
39
+ it "builds the site" do
40
+ execute_bin({}, "build")
41
+ expect(File).to exist("#{tmp_dir}/_site/index.html")
42
+ end
43
+ end
@@ -0,0 +1,43 @@
1
+ require "spec_helper"
2
+
3
+ describe "bunto site" do
4
+ include Rack::Test::Methods
5
+
6
+ def app
7
+ BuntoAuth::BuntoSite
8
+ end
9
+
10
+ before do
11
+ setup_tmp_dir
12
+ File.write File.expand_path("_config.yml", tmp_dir), "foo: bar"
13
+ `bundle exec bunto build`
14
+ end
15
+
16
+ it "serves the index" do
17
+ get "/"
18
+ expect(last_response.body).to eql("My awesome site")
19
+ end
20
+
21
+ it "serves a page" do
22
+ get "/index.html"
23
+ expect(last_response.body).to eql("My awesome site")
24
+ end
25
+
26
+ it "serves a directory index" do
27
+ get "/some_dir"
28
+ expect(last_response.body).to eql("My awesome directory")
29
+ end
30
+
31
+ it "serves the default 404" do
32
+ get "/a-bad-path"
33
+ expect(last_response.status).to eql(404)
34
+ expect(last_response.body).to eql("<h1>Not Found</h1>")
35
+ end
36
+
37
+ it "serves a custom 404" do
38
+ File.write File.expand_path("_site/404.html", tmp_dir), "My custom 404"
39
+ get "/a-bad-path"
40
+ expect(last_response.status).to eql(404)
41
+ expect(last_response.body).to eql("My custom 404")
42
+ end
43
+ end
@@ -0,0 +1,75 @@
1
+ require "spec_helper"
2
+
3
+ describe "commands" do
4
+ before do
5
+ setup_tmp_dir
6
+ end
7
+
8
+ it "should find the template directory" do
9
+ expect(File.directory?(BuntoAuth::Commands.source)).to eql(true)
10
+ expect(File).to exist("#{BuntoAuth::Commands.source}/config.ru")
11
+ end
12
+
13
+ it "should know the destination directory" do
14
+ expect(BuntoAuth::Commands.destination).to eql(tmp_dir)
15
+ end
16
+
17
+ it "should execute a command" do
18
+ expect(BuntoAuth::Commands.execute_command("ls")).to match(%r!index\.html!)
19
+ end
20
+
21
+ it "should retrieve a team's ID" do
22
+ stub_request(:get, "https://api.github.com/orgs/batler-test-org/teams?per_page=100")
23
+ .to_return(:status => 204, :body => [{ :slug => "test-team", :id => 1 }])
24
+ expect(BuntoAuth::Commands.team_id("batler-test-org", "test-team")).to eql(1)
25
+ end
26
+
27
+ it "should copy the template files" do
28
+ expect(File).to_not exist("#{tmp_dir}/config.ru")
29
+ BuntoAuth::Commands.copy_templates
30
+ expect(File).to exist("#{tmp_dir}/config.ru")
31
+ expect(File).to exist("#{tmp_dir}/Rakefile")
32
+ expect(File).to exist("#{tmp_dir}/.gitignore")
33
+ end
34
+
35
+ it "should know when a directory's changed" do
36
+ `git init`
37
+ `git add .`
38
+ `git commit -m 'initial commit'`
39
+ expect(BuntoAuth::Commands.changed?).to eql(false)
40
+ `touch config.ru`
41
+ expect(BuntoAuth::Commands.changed?).to eql(true)
42
+ end
43
+
44
+ it "knows when env vars are set" do
45
+ var = "SOME_ENV_VAR"
46
+
47
+ ENV.delete(var)
48
+ expect(BuntoAuth::Commands.env_var_set?(var)).to eql(false)
49
+
50
+ ENV[var] = "bar"
51
+ expect(BuntoAuth::Commands.env_var_set?(var)).to eql(true)
52
+
53
+ ENV[var] = ""
54
+ expect(BuntoAuth::Commands.env_var_set?(var)).to eql(false)
55
+
56
+ ENV[var] = nil
57
+ expect(BuntoAuth::Commands.env_var_set?(var)).to eql(false)
58
+ end
59
+
60
+ it "knows when there's a heroku remote" do
61
+ `git init`
62
+ expect(BuntoAuth::Commands.heroku_remote_set?).to eql(false)
63
+ `git remote add heroku https://example.com`
64
+ expect(BuntoAuth::Commands.heroku_remote_set?).to eql(true)
65
+ end
66
+
67
+ it "should make an initial commit" do
68
+ `git init`
69
+ `touch foo.md`
70
+ `git add foo.md`
71
+ BuntoAuth::Commands.initial_commit
72
+ output = BuntoAuth::Commands.execute_command "git", "log"
73
+ expect(output).to match(%r!\[Bunto Auth\] Initial setup!)
74
+ end
75
+ end