mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-09-17 11:19:15 +00:00
Merge pull request #27 from SAP/bug6181
bug6181: Allow wiki login via GitHub credentials
This commit is contained in:
+1
-1
@@ -9,5 +9,5 @@ RequiredBy=multi-user.target
|
||||
[Service]
|
||||
Type=exec
|
||||
RemainAfterExit=true
|
||||
ExecStart=su - wiki -c "cd /home/wiki && rackup -p 4567 /home/wiki/config.ru"
|
||||
ExecStart=su - wiki -c "cd /home/wiki && ./serve.sh"
|
||||
ExecStop=/bin/kill -SIGTERM "$MAINPID"
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
source "https://rubygems.org"
|
||||
|
||||
ruby "3.2.8"
|
||||
|
||||
gem "gollum", "5.3.2"
|
||||
|
||||
gem "sinatra", "2.2.4"
|
||||
gem "sinatra-contrib", "2.2.4"
|
||||
|
||||
gem "rack", "2.2.21"
|
||||
gem "rack-protection", "2.2.4"
|
||||
gem "rack-session", "~> 1.0"
|
||||
|
||||
gem "webrick", "1.9.1"
|
||||
|
||||
gem "redis", "5.4.1"
|
||||
gem "redis-store", "1.11.0"
|
||||
gem "redis-rack", "2.1.2"
|
||||
|
||||
gem "rugged", "1.9.0"
|
||||
|
||||
gem "github-markup", "4.0.2"
|
||||
gem "kramdown", "2.5.1"
|
||||
gem "kramdown-parser-gfm", "1.1.0"
|
||||
|
||||
gem "mustache", "1.1.1"
|
||||
gem "mustache-sinatra", "2.0.0"
|
||||
|
||||
gem "rest-client", "2.1.0"
|
||||
gem 'rufo'
|
||||
@@ -0,0 +1,24 @@
|
||||
# Internal Wiki
|
||||
|
||||
We use a Ruby based tool called Gollum for our wiki (one wiki to rule them all 🙄).
|
||||
It provides a nice UI, indexing and versions all changes in Git.
|
||||
|
||||
We have added some authentication and access control as a sort of middleware.
|
||||
This is done via the GitHub OAuth process and some APIs.
|
||||
|
||||
## The Process
|
||||
Users navigate to `/login` (or are automatically redirected here if they are logged out and they try to access a path for modifying a resource) and are redirected to GitHub, starting the OAuth process. They have to authenticate with their chosen GitHub credentials and are then redirected back to the wiki.
|
||||
If a user tries to read a resource or its history then they can access anything, but they must have push access to the Sailing Analytics repository to modify a resource (e.g. rename, create, modify).
|
||||
|
||||
## Installation
|
||||
Run `bundle install` in the wiki home directory as the user who will start the wiki and make sure the Gemfile is present.
|
||||
|
||||
## Files
|
||||
* The `templates` dir is necessary for adding the logout button. A custom dir can be specified by modifying the `config.ru`.
|
||||
* The `app.rb` handles the auth and provides an allow list for user paths
|
||||
* `config.ru` handles configuration and setup as you might guess.
|
||||
* `Gemfile` all packages and versions.
|
||||
* `server.sh` launches the wiki via Bundle.
|
||||
|
||||
## Running
|
||||
First ensure the secrets specified at the start of app.rb (`ENV[<name>]`) are exported in a secrets file in the same directory. Then, as the user who owns the git repository that backs the Gollum wiki, run the `serve.sh` script.
|
||||
@@ -1,99 +1,223 @@
|
||||
require 'gollum/app'
|
||||
require 'digest/sha1'
|
||||
require "gollum/app"
|
||||
require "digest/sha1"
|
||||
require "logger"
|
||||
require "rest-client"
|
||||
require "rack/session/redis"
|
||||
require "base64"
|
||||
|
||||
|
||||
#__DIR__ = File.expand_path(File.dirname(__FILE__))
|
||||
#$: << __DIR__
|
||||
class App < Precious::App
|
||||
User = Struct.new(:name, :email, :password_hash, :can_write)
|
||||
before { authenticate! }
|
||||
before /edit/ do authorize_write! ; end
|
||||
before do
|
||||
session['gollum.author'] = {
|
||||
:name => "%s" % settings.loggedInUser,
|
||||
:email => "%s" % settings.loggedInUserEmail,
|
||||
}
|
||||
use Rack::Session::Pool, expire_after: 3600, httponly: true #, secure: true
|
||||
|
||||
# use Rack::Session::Redis,
|
||||
# :redis_server => "redis://127.0.0.1:6379/0",
|
||||
# :expires_in => 3600
|
||||
|
||||
LOGGER = Logger.new("/home/wiki/wiki_log.txt")
|
||||
CLIENT_ID = ENV["CLIENT_ID"]
|
||||
CLIENT_SECRET = ENV["CLIENT_SECRET"]
|
||||
REDIRECT_URL = "https://wiki.sapsailing.com/callback"
|
||||
ACCESS_TOKEN = ENV["ACCESS_TOKEN"]
|
||||
|
||||
REPO_OWNER = "SAP"
|
||||
REPO_NAME = "sailing-analytics"
|
||||
before { check! }
|
||||
before "/gollum/(edit|create|rename|delete)/*" do authorize_write end
|
||||
before do
|
||||
if session[:email] && session[:name]
|
||||
session["gollum.author"] = {
|
||||
:name => session[:name],
|
||||
:email => session[:email],
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
get "/logout" do
|
||||
if session[:access_token]
|
||||
revoke_access_token(token)
|
||||
end
|
||||
session.clear()
|
||||
"logged out"
|
||||
end
|
||||
|
||||
get "/login" do
|
||||
session[:oauth_state] = {
|
||||
:state => SecureRandom.hex(16),
|
||||
:expiry => Time.now + (60 * 5),
|
||||
}
|
||||
params = {
|
||||
client_id: CLIENT_ID,
|
||||
scope: "user:email",
|
||||
state: session[:oauth_state][:state],
|
||||
redirect_uri: REDIRECT_URL,
|
||||
}
|
||||
uri = URI::HTTPS.build(
|
||||
host: "github.com",
|
||||
path: "/login/oauth/authorize",
|
||||
query: URI.encode_www_form(params),
|
||||
)
|
||||
redirect uri.to_s()
|
||||
end
|
||||
|
||||
get "/callback" do
|
||||
if session[:logged_in]
|
||||
# Ensures cancel works in editor after login.
|
||||
if session[:prev]
|
||||
LOGGER.debug(session[:prev])
|
||||
prev = session[:prev].dup
|
||||
stripped_prev = prev.sub("/gollum/edit", "")
|
||||
redirect stripped_prev
|
||||
end
|
||||
end
|
||||
halt 400, "error" if params[:error]
|
||||
halt 400, "Missing code" unless params[:code]
|
||||
halt 403, "Old state" unless session[:oauth_state] && session[:oauth_state][:expiry] > Time.now
|
||||
halt 403, "Invalid OAuth state" unless session[:oauth_state] && session[:oauth_state][:state] == params[:state]
|
||||
|
||||
session.delete(:oauth_state)
|
||||
|
||||
result = JSON.parse(RestClient.post("https://github.com/login/oauth/access_token",
|
||||
{
|
||||
:client_id => CLIENT_ID,
|
||||
:client_secret => CLIENT_SECRET,
|
||||
:code => params[:code],
|
||||
:redirect_uri => REDIRECT_URL,
|
||||
},
|
||||
:accept => :json))
|
||||
scopes = result["scope"].split(",")
|
||||
if scopes.include?("user:email") && result["access_token"]
|
||||
access_token = result["access_token"]
|
||||
fetch_and_set_user_email(access_token)
|
||||
fetch_and_set_user_name_and_id(access_token)
|
||||
session[:logged_in] = true
|
||||
revoke_access_token(access_token)
|
||||
session.delete(:access_token)
|
||||
end
|
||||
|
||||
if session[:prev]
|
||||
redirect session[:prev].sub(/\/gollum\/(rename|delete)/, "")
|
||||
end
|
||||
|
||||
redirect "/"
|
||||
end
|
||||
|
||||
helpers do
|
||||
def authenticate!
|
||||
public_urls=IO.readlines 'public.txt'
|
||||
public_urls.each {|url|
|
||||
if self.env['PATH_INFO'] == url.slice(0, url.length-1)
|
||||
puts "Allowing " + url
|
||||
return
|
||||
end
|
||||
def public_path?(path)
|
||||
if path == "/"
|
||||
return true
|
||||
end
|
||||
public_starts = ["/Home", "/wiki", "/favicon.ico"]
|
||||
public_starts.any? { |link| path.start_with?(link) }
|
||||
end
|
||||
|
||||
if self.env['PATH_INFO'].start_with?('/wiki/images') ||
|
||||
self.env['PATH_INFO'].start_with?('/favicon.ico')
|
||||
return
|
||||
end
|
||||
}
|
||||
if self.env['PATH_INFO'].split('/')[1] == 'gollum' && self.env['PATH_INFO'].split('/')[2] == 'assets'
|
||||
def asset_path?(path)
|
||||
non_page_patterns = [%r{\A/gollum/(assets|commit|history|last_commit_info).*}, %r{\A/gollum/search}, %r{\A/gollum/latest_changes\z}]
|
||||
non_page_patterns.any? { |pattern| pattern.match(path) }
|
||||
end
|
||||
|
||||
def auth_path?(path)
|
||||
auth_paths = [%r{\A/gollum/(edit|create|rename|delete)/.*\z}, %r{\A/gollum/(overview|preview)}, %r{\A/gollum/create}]
|
||||
auth_paths.any? { |pattern| pattern.match(path) }
|
||||
end
|
||||
|
||||
def login_path?(path)
|
||||
%r{\A/(login|callback|logout|cancel)\z}.match?(path)
|
||||
end
|
||||
|
||||
def check!
|
||||
path = env["PATH_INFO"].dup
|
||||
LOGGER.debug(path)
|
||||
return if login_path?(path)
|
||||
return if asset_path?(path)
|
||||
isPublicPath = public_path?(path)
|
||||
isAuthPath = auth_path?(path)
|
||||
if isPublicPath || isAuthPath
|
||||
session[:prev] = path
|
||||
return
|
||||
end
|
||||
@_auth = Rack::Auth::Basic::Request.new(request.env)
|
||||
if self.env['PATH_INFO'].split('/').length >=2 &&
|
||||
(self.env['PATH_INFO'].split('/')[1] != 'wiki' &&
|
||||
self.env['PATH_INFO'].split('/')[2] != 'wiki' &&
|
||||
self.env['PATH_INFO'].split('/')[1] != 'home' &&
|
||||
self.env['PATH_INFO'].split('/')[2] != 'home' &&
|
||||
self.env['PATH_INFO'].split('/')[1] != 'Home' &&
|
||||
self.env['PATH_INFO'].split('/')[2] != 'Home' &&
|
||||
self.env['PATH_INFO'].split('/')[1] != 'Home.md' &&
|
||||
self.env['PATH_INFO'].split('/')[1] != 'search' &&
|
||||
self.env['PATH_INFO'].split('/')[2] != 'search' &&
|
||||
self.env['PATH_INFO'].split('/')[1] != 'edit' &&
|
||||
self.env['PATH_INFO'].split('/')[2] != 'edit' &&
|
||||
self.env['PATH_INFO'].split('/')[1] != 'preview' &&
|
||||
self.env['PATH_INFO'].split('/')[2] != 'preview' &&
|
||||
(self.env['PATH_INFO'].split('/')[1] != 'gollum' ||
|
||||
(self.env['PATH_INFO'].split('/')[2] != 'create' &&
|
||||
(self.env['PATH_INFO'].split('/')[2] != 'overview' || self.env['PATH_INFO'].split('/')[3] != 'wiki'))))
|
||||
throw(:halt, [403, 'Forbidden - You can not access anything outside wiki/ path.'])
|
||||
halt 404, "You cannot access anything outside wiki/ path."
|
||||
end
|
||||
|
||||
def authorize_write
|
||||
LOGGER.debug("Checking auth before writing")
|
||||
|
||||
if !session[:logged_in]
|
||||
if env["PATH_INFO"].dup.match(%r{/gollum/delete/.*})
|
||||
halt 401, "Unauthorized"
|
||||
end
|
||||
redirect "/login"
|
||||
end
|
||||
if @_auth.provided?
|
||||
end
|
||||
if @_auth.provided? && @_auth.basic? && @_auth.credentials && @user = detected_user(@_auth.credentials)
|
||||
Precious::App.set(:loggedInUser, @user.name)
|
||||
Precious::App.set(:loggedInUserEmail, @user.email)
|
||||
return @user
|
||||
else
|
||||
response['WWW-Authenticate'] = %(Basic realm="Gollum Wiki")
|
||||
throw(:halt, [401, "Not authorized\n"])
|
||||
halt 403, "Forbidden" unless user_can_write()
|
||||
end
|
||||
|
||||
def user_can_write()
|
||||
return false unless session[:logged_in] && session[:name]
|
||||
response = github_api_get("/repos/#{REPO_OWNER}/#{REPO_NAME}/collaborators/#{session[:name]}/permission",
|
||||
ACCESS_TOKEN)
|
||||
return false unless response
|
||||
LOGGER.debug("response received")
|
||||
result = JSON.parse(response)
|
||||
LOGGER.debug("checking permission")
|
||||
result.dig("user", "permissions", "push") == true
|
||||
end
|
||||
|
||||
def fetch_and_set_user_email(access_token)
|
||||
response = github_api_get("/user/emails", access_token)
|
||||
return unless response
|
||||
emails = JSON.parse(response)
|
||||
if emails[0] && emails[0]["email"]
|
||||
session[:email] = emails[0]["email"]
|
||||
LOGGER.debug("email is #{session[:email]}")
|
||||
end
|
||||
end
|
||||
|
||||
def authorize_write!
|
||||
throw(:halt, [403, "Forbidden\n"]) unless @user.can_write
|
||||
end
|
||||
|
||||
def users
|
||||
@_users ||= settings.authorized_users.map {|u| User.new(*u) }
|
||||
end
|
||||
|
||||
def detected_user(credentials)
|
||||
users.detect do |u|
|
||||
[u.email, u.password_hash] ==
|
||||
[credentials[0], Digest::SHA1.hexdigest(credentials[1])]
|
||||
def fetch_and_set_user_name_and_id(access_token)
|
||||
response = github_api_get("/user", access_token)
|
||||
return unless response
|
||||
user_details = JSON.parse(response)
|
||||
if user_details["login"] && user_details["id"]
|
||||
session[:user_id] = user_details["id"]
|
||||
session[:name] = user_details["login"]
|
||||
LOGGER.debug("user #{session[:email]} logged in")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def commit_
|
||||
{
|
||||
:message => params[:message],
|
||||
# :name => @user.name,
|
||||
:email => @user.email
|
||||
}
|
||||
def github_api_get(path, access_token)
|
||||
uri = URI::HTTPS.build(
|
||||
host: "api.github.com",
|
||||
path: path,
|
||||
)
|
||||
RestClient.get(uri.to_s(),
|
||||
{
|
||||
:Authorization => "Bearer #{access_token}",
|
||||
})
|
||||
rescue RestClient::Unauthorized, RestClient::Forbidden
|
||||
LOGGER.warn("GitHub auth failed for #{path}")
|
||||
nil
|
||||
rescue RestClient::ExceptionWithResponse => e
|
||||
LOGGER.error("GitHub API error #{e.response.code} for #{path}")
|
||||
nil
|
||||
rescue StandardError => e
|
||||
LOGGER.error("GitHub request failed: #{e.message}")
|
||||
nil
|
||||
end
|
||||
|
||||
def revoke_access_token(token)
|
||||
uri = URI::HTTPS.build(
|
||||
host: "api.github.com",
|
||||
path: "/applications/#{CLIENT_ID}/token",
|
||||
)
|
||||
basicAuth = Base64.strict_encode64("#{CLIENT_ID}:#{CLIENT_SECRET}")
|
||||
RestClient::Request.execute(
|
||||
method: :delete,
|
||||
url: uri.to_s(),
|
||||
payload: {
|
||||
:access_token => token,
|
||||
}.to_json(),
|
||||
headers: {
|
||||
:Authorization => "Basic #{basicAuth}",
|
||||
:accept => "application/vnd.github.v3+json",
|
||||
},
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
##set author
|
||||
#class Precious::App
|
||||
# before do
|
||||
# session['gollum.author'] = {
|
||||
# :name => "%s" % settings.loggedInUser,
|
||||
# :email => "%s@example.com" % settings.loggedInUser,
|
||||
# }
|
||||
# end
|
||||
#End
|
||||
|
||||
@@ -28,11 +28,6 @@
|
||||
#use Gollum::Auth, users, options
|
||||
#
|
||||
## That's it. The rest is for gollum only.
|
||||
#gollum_path = "/home/wiki/gitwiki"
|
||||
#wiki_options = {:universal_toc => false}
|
||||
#Precious::App.set(:gollum_path, gollum_path)
|
||||
#Precious::App.set(:wiki_options, wiki_options)
|
||||
#run Precious::App
|
||||
|
||||
require 'rubygems'
|
||||
require 'gollum/app'
|
||||
@@ -48,7 +43,7 @@ Gollum::Page.send :remove_const, :FORMAT_NAMES if defined? Gollum::Page::FORMAT_
|
||||
#}
|
||||
|
||||
gollum_path = "/home/wiki/gitwiki"
|
||||
wiki_options = {universal_toc: false, ref: 'main'}
|
||||
wiki_options = {universal_toc: false, ref: 'main', template_dir: "./templates"}
|
||||
Precious::App.set(:gollum_path, gollum_path)
|
||||
Precious::App.set(:wiki_options, wiki_options)
|
||||
Precious::App.set(:authorized_users, YAML.load_file(File.expand_path('users.yml', File.expand_path(File.dirname(__FILE__)))))
|
||||
@@ -57,12 +52,3 @@ Precious::App.set(:loggedInUserEmail, "wiki@sapsailing.com");
|
||||
App.set(:default_markup, :markdown) # set your favorite markup language
|
||||
run App
|
||||
|
||||
#require 'rubygems'
|
||||
#require 'gollum/app'
|
||||
#
|
||||
#gollum_path = "/home/wiki/gitwiki"
|
||||
#wiki_options = {:universal_toc => false}
|
||||
#Precious::App.set(:gollum_path, gollum_path)
|
||||
#Precious::App.set(:default_markup, :markdown) # set your favorite markup language
|
||||
#Precious::App.set(:wiki_options, wiki_options)
|
||||
#run Precious::App
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
#!/bin/bash
|
||||
# kill any running gollums
|
||||
kill -9 `ps axlw | grep rackup | grep wiki | awk '{ print $3; }'`
|
||||
rm /home/wiki/wiki_log.txt
|
||||
# start gollum as a background process
|
||||
# you can pipe output to /dev/null instead, if you don't want a log
|
||||
cd /home/wiki
|
||||
. secrets
|
||||
#nohup rackup -p 4567 /home/wiki/config.ru 1>nohup.out 2>&1 &
|
||||
nohup bundle exec rackup -p 4567 /home/wiki/config.ru &
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
<div id="wiki-content" class="px-2 px-lg-0">
|
||||
<h1 class="header-title text-center text-md-left pt-4">
|
||||
{{page_header}}
|
||||
</h1>
|
||||
<div class="breadcrumb">{{{breadcrumb}}}</div>
|
||||
|
||||
<div class="{{#has_header}}has-header{{/has_header}}{{#has_footer}} has-footer{{/has_footer}}{{#has_sidebar}} has-sidebar has-{{bar_side}}bar{{/has_sidebar}}{{#has_toc}} has-toc{{/has_toc}}">
|
||||
{{#has_toc}}
|
||||
<div id="wiki-toc-main">
|
||||
{{{toc_content}}}
|
||||
</div>
|
||||
{{/has_toc}}
|
||||
<div id="wiki-body" class="gollum-{{format}}-content">
|
||||
{{#has_header}}
|
||||
<div id="wiki-header" class="gollum-{{header_format}}-content">
|
||||
<div id="header-content" class="markdown-body">
|
||||
{{{header_content}}}
|
||||
</div>
|
||||
</div>
|
||||
{{/has_header}}
|
||||
<div class="main-content clearfix container-lg">
|
||||
<div class="markdown-body {{#header_enum?}}header-enum{{/header_enum?}} {{#has_sidebar}}float-md-{{body_side}} col-md-9{{/has_sidebar}}" {{#header_enum?}}style="--header-enum-style:{{header_enum_style}};"{{/header_enum?}}>
|
||||
{{{rendered_metadata}}}
|
||||
{{{content}}}
|
||||
</div>
|
||||
{{#has_sidebar}}
|
||||
<div id="wiki-sidebar" class="Box Box--condensed float-md-{{body_side}} col-md-3">
|
||||
<div id="sidebar-content" class="gollum-{{sidebar_format}}-content markdown-body px-4">
|
||||
{{{sidebar_content}}}
|
||||
</div>
|
||||
</div>
|
||||
{{/has_sidebar}}
|
||||
</div>
|
||||
</div>
|
||||
{{#has_footer}}
|
||||
<div id="wiki-footer" class="gollum-{{footer_format}}-content my-2">
|
||||
<div id="footer-content" class="Box Box-condensed markdown-body px-4">
|
||||
{{{footer_content}}}
|
||||
</div>
|
||||
</div>
|
||||
{{/has_footer}}
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div id="footer" class="pt-4">
|
||||
{{^historical}}
|
||||
{{^preview}}
|
||||
<a href="/logout">logout</a>
|
||||
<p id="last-edit"><div class="dotted-spinner hidden"></div> <a id="page-info-toggle" data-pagepath="{{escaped_url_path}}">When was this page last modified?</a></p>
|
||||
{{#allow_editing}}
|
||||
<p>
|
||||
<a id="delete-link" href="{{escaped_url_path}}" data-confirm="Are you sure you want to delete this page?"><span>Delete this Page</span></a>
|
||||
</p>
|
||||
{{/allow_editing}}
|
||||
{{/preview}}
|
||||
{{/historical}}
|
||||
{{#historical}}
|
||||
<p>This version of the page was edited by <b>{{author}}</b> at <time datetime="{{datetime}}" data-format="{{date_format}}">{{date}}</time>. <a href="{{full_url_path}}">View the most recent version.</a></p>
|
||||
{{/historical}}
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
Executable
+88
@@ -0,0 +1,88 @@
|
||||
#!/bin/bash
|
||||
echo "Content-Type: text/html"
|
||||
echo ""
|
||||
# Read secrets:
|
||||
. ~/secrets
|
||||
# ==== CONFIG for OAuth App wiki.sapsailing.com: ====
|
||||
CLIENT_ID="${GITHUB_OAUTH_CLIENT_ID}"
|
||||
CLIENT_SECRET="${GITHUB_OAUTH_CLIENT_SECRET}"
|
||||
REDIRECT_URI="https://git.sapsailing.com/cgi-bin/github_oauth.sh"
|
||||
# ===================================================
|
||||
STATES_FILE=/tmp/github_oauth_states
|
||||
# Parse QUERY_STRING for code
|
||||
QUERY="$QUERY_STRING"
|
||||
CODE=""
|
||||
STATE_PARAM=""
|
||||
IFS='&' read -ra KV <<< "$QUERY"
|
||||
for pair in "${KV[@]}"; do
|
||||
key="${pair%%=*}"
|
||||
val="${pair#*=}"
|
||||
if [ "$key" = "code" ]; then
|
||||
CODE="$val"
|
||||
elif [ "$key" = "state" ]; then
|
||||
STATE_PARAM="$val"
|
||||
fi
|
||||
done
|
||||
# Checking for code parameter; if not found, start the flow
|
||||
if [ -z "$CODE" ]; then
|
||||
# No code → show login page
|
||||
STATE=$(openssl rand -hex 16)
|
||||
echo "${STATE}" >>"${STATES_FILE}"
|
||||
AUTH_URL="https://github.com/login/oauth/authorize?client_id=${CLIENT_ID}&redirect_uri=${REDIRECT_URI}&scope=read:user,user:email&state=${STATE}"
|
||||
cat <<EOF
|
||||
<html><head><title>GitHub OAuth Login</title></head>
|
||||
<body>
|
||||
<h2>Login with GitHub</h2>
|
||||
<p><a href="${AUTH_URL}">Authorize this app to access your GitHub account</a></p>
|
||||
</body></html>
|
||||
EOF
|
||||
exit 0
|
||||
else
|
||||
if grep -q "${STATE_PARAM}" "${STATES_FILE}"; then
|
||||
sed -i '/'${STATE_PARAM}'/d' "${STATES_FILE}"
|
||||
# Got a code → exchange it for an access token
|
||||
TOKEN_JSON=$(curl -s -X POST https://github.com/login/oauth/access_token \
|
||||
-H "Accept: application/json" \
|
||||
-d "client_id=${CLIENT_ID}" \
|
||||
-d "client_secret=${CLIENT_SECRET}" \
|
||||
-d "code=${CODE}" \
|
||||
-d "redirect_uri=${REDIRECT_URI}" )
|
||||
ACCESS_TOKEN=$(echo "$TOKEN_JSON" | jq -r '.access_token')
|
||||
if [ "$ACCESS_TOKEN" = "null" ] || [ -z "$ACCESS_TOKEN" ]; then
|
||||
cat <<EOF
|
||||
<html><body>
|
||||
<h3>Failed to obtain access token.</h3>
|
||||
<pre>${TOKEN_JSON}</pre>
|
||||
</body></html>
|
||||
EOF
|
||||
exit 1
|
||||
else
|
||||
# Use token to get user info
|
||||
USER_JSON=$(curl -s -H "Authorization: token ${ACCESS_TOKEN}" -H "Accept: application/vnd.github+json" https://api.github.com/user)
|
||||
LOGIN=$(echo "$USER_JSON" | jq -r '.login')
|
||||
cat <<EOF
|
||||
<html><head><title>GitHub OAuth Success</title></head>
|
||||
<body>
|
||||
<h2>Welcome, ${LOGIN}!</h2>
|
||||
<p>The state param ${STATE_PARAM} was found in our ${STATES_FILE}:</p>
|
||||
<pre>$(cat "${STATES_FILE}")</pre>
|
||||
<p>You have successfully authenticated with GitHub.</p>
|
||||
<p>Your token JSON was:</p>
|
||||
<pre>${TOKEN_JSON}</pre>
|
||||
<p><strong>Access Token:</strong> ${ACCESS_TOKEN}</p>
|
||||
<p>You can now use this token to make API calls on behalf of this user.</p>
|
||||
<pre>${USER_JSON}</pre>
|
||||
</body></html>
|
||||
EOF
|
||||
fi
|
||||
else
|
||||
# The ${STATE_PARAM} was not found in ${STATES_FILE}, so this may be an attack
|
||||
cat <<EOF
|
||||
<html><body>
|
||||
<h3>Failed to find state; attack?</h3>
|
||||
<pre>${STATE_PARAM}</pre>
|
||||
</body></html>
|
||||
EOF
|
||||
exit 2
|
||||
fi
|
||||
fi
|
||||
+2
-1
@@ -35,7 +35,7 @@ terminationCheck() {
|
||||
}
|
||||
if [[ "$#" -ne 4 ]]; then
|
||||
echo "4 arguments required. Please check comment description for further details."
|
||||
echo "Example usage: setup-central-reverse-proxy.sh 1.2.3.4 0OcJ1938QE5it875kjlQe7HnzQ6740jsnMEVzowjZrs= 18.170.25.225 /home/sailing/code"
|
||||
echo "Example usage: setup-central-reverse-proxy.sh 1.2.3.4 0OcJ1938QE5it875kjlQe7HnzQ6740jsnMEVzowjZrs= 54.229.94.254 /home/wiki/gitwiki"
|
||||
exit 2
|
||||
fi
|
||||
echo "Make sure the instance is in the same AZ as the existing reverse proxy, so the volumes can be switched over."
|
||||
@@ -65,6 +65,7 @@ yum group install -y "Development Tools"
|
||||
yum install -y ruby ruby-devel libicu libicu-devel zlib zlib-devel git cmake openssl-devel libyaml-devel
|
||||
gem install gollum -v 5.3.2
|
||||
gem update --system 3.5.7
|
||||
su - wiki -c "cd /home/wiki && bundle install"
|
||||
cd /home
|
||||
# copy bugzilla
|
||||
scp -o StrictHostKeyChecking=no root@sapsailing.com:/var/www/static/bugzilla-5.2.tar.gz /usr/local/src
|
||||
|
||||
Reference in New Issue
Block a user